From 378738aaa9924d0b95e2c57f27cbad2b2e644282 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 26 Apr 2022 09:34:34 -0500 Subject: =?UTF-8?q?Issue=20#1829=20-=20Revert=20=E2=80=9CIssue=20#1751=20-?= =?UTF-8?q?=20Remove=20Mac=20code=20behind=20MOZ=5FWIDGET=5FTOOLKIT=20=3D?= =?UTF-8?q?=3D=20'cocoa=E2=80=99=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1fe9c19305dadf2d5bcaa0e589fcd250389dfa8a. --- accessible/base/moz.build | 4 + accessible/generic/moz.build | 4 + accessible/html/moz.build | 4 + accessible/ipc/moz.build | 4 + accessible/ipc/other/moz.build | 4 + accessible/mac/ARIAGridAccessibleWrap.h | 22 + accessible/mac/AccessibleWrap.h | 103 ++ accessible/mac/AccessibleWrap.mm | 256 +++++ accessible/mac/ApplicationAccessibleWrap.h | 22 + accessible/mac/DocAccessibleWrap.h | 25 + accessible/mac/DocAccessibleWrap.mm | 21 + accessible/mac/HTMLTableAccessibleWrap.h | 24 + accessible/mac/HyperTextAccessibleWrap.h | 20 + accessible/mac/ImageAccessibleWrap.h | 22 + accessible/mac/MacUtils.h | 26 + accessible/mac/MacUtils.mm | 32 + accessible/mac/Platform.mm | 174 +++ accessible/mac/RootAccessibleWrap.h | 34 + accessible/mac/RootAccessibleWrap.mm | 53 + accessible/mac/TextLeafAccessibleWrap.h | 19 + accessible/mac/XULListboxAccessibleWrap.h | 20 + accessible/mac/XULMenuAccessibleWrap.h | 19 + accessible/mac/XULTreeGridAccessibleWrap.h | 20 + accessible/mac/moz.build | 44 + accessible/mac/mozAccessible.h | 181 +++ accessible/mac/mozAccessible.mm | 1197 +++++++++++++++++++ accessible/mac/mozAccessibleProtocol.h | 69 ++ accessible/mac/mozActionElements.h | 37 + accessible/mac/mozActionElements.mm | 340 ++++++ accessible/mac/mozDocAccessible.h | 31 + accessible/mac/mozDocAccessible.mm | 111 ++ accessible/mac/mozHTMLAccessible.h | 16 + accessible/mac/mozHTMLAccessible.mm | 141 +++ accessible/mac/mozTableAccessible.h | 28 + accessible/mac/mozTableAccessible.mm | 281 +++++ accessible/mac/mozTextAccessible.h | 17 + accessible/mac/mozTextAccessible.mm | 627 ++++++++++ accessible/moz.build | 2 + accessible/xpcom/moz.build | 4 + accessible/xul/moz.build | 4 + db/sqlite3/src/moz.build | 4 + embedding/components/build/moz.build | 5 + embedding/components/printingui/mac/moz.build | 15 + .../components/printingui/mac/nsPrintProgress.cpp | 213 ++++ .../components/printingui/mac/nsPrintProgress.h | 44 + .../printingui/mac/nsPrintProgressParams.cpp | 47 + .../printingui/mac/nsPrintProgressParams.h | 28 + .../printingui/mac/nsPrintingPromptService.h | 43 + .../printingui/mac/nsPrintingPromptServiceX.mm | 128 +++ embedding/components/printingui/moz.build | 2 + gfx/cairo/cairo/src/moz.build | 4 +- gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp | 107 ++ gfx/layers/basic/MacIOSurfaceTextureHostBasic.h | 97 ++ gfx/layers/ipc/ShadowLayerUtilsMac.cpp | 40 + gfx/layers/moz.build | 25 + gfx/layers/opengl/GLManager.cpp | 70 ++ gfx/layers/opengl/GLManager.h | 44 + gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp | 140 +++ gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h | 58 + gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp | 180 +++ gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h | 114 ++ gfx/skia/generate_mozbuild.py | 3 +- gfx/skia/moz.build | 3 +- image/decoders/icon/mac/moz.build | 10 + image/decoders/icon/mac/nsIconChannel.h | 59 + image/decoders/icon/mac/nsIconChannelCocoa.mm | 565 +++++++++ image/decoders/icon/moz.build | 3 + image/decoders/moz.build | 3 + intl/locale/mac/moz.build | 15 + intl/locale/mac/nsCollationMacUC.cpp | 253 ++++ intl/locale/mac/nsCollationMacUC.h | 44 + intl/locale/mac/nsDateTimeFormatMac.cpp | 266 +++++ intl/locale/mac/nsDateTimeFormatMac.h | 61 + intl/locale/mac/nsMacCharset.cpp | 59 + intl/locale/moz.build | 2 + intl/lwbrk/moz.build | 4 + intl/lwbrk/nsCarbonBreaker.cpp | 44 + js/xpconnect/shell/moz.build | 5 + js/xpconnect/shell/xpcshellMacUtils.h | 8 + js/xpconnect/shell/xpcshellMacUtils.mm | 18 + layout/build/moz.build | 4 + layout/reftests/reftest.list | 3 + mailnews/base/ispdata/moz.build | 4 +- mailnews/base/src/moz.build | 2 + mailnews/base/src/nsMessengerOSXIntegration.h | 63 + mailnews/base/src/nsMessengerOSXIntegration.mm | 700 ++++++++++++ mailnews/build/moz.build | 4 + mailnews/compose/src/moz.build | 10 + mailnews/compose/src/nsMsgAppleCodes.h | 106 ++ mailnews/compose/src/nsMsgAppleDouble.h | 207 ++++ mailnews/compose/src/nsMsgAppleDoubleEncode.cpp | 266 +++++ mailnews/compose/src/nsMsgAppleEncode.cpp | 703 ++++++++++++ mailnews/import/build/moz.build | 7 + media/libcubeb/src/cubeb_osx_run_loop.c | 11 + media/libcubeb/src/cubeb_osx_run_loop.h | 22 + media/libcubeb/src/moz.build | 4 + netwerk/base/NetworkInfoServiceCocoa.cpp | 103 ++ netwerk/base/moz.build | 9 + netwerk/base/nsURLHelperOSX.cpp | 216 ++++ netwerk/build/moz.build | 7 +- netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp | 779 +++++++++++++ netwerk/dns/mdns/libmdns/MDNSResponderOperator.h | 152 +++ netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp | 302 +++++ netwerk/dns/mdns/libmdns/MDNSResponderReply.h | 164 +++ netwerk/dns/mdns/libmdns/moz.build | 38 +- netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp | 262 +++++ netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h | 49 + netwerk/streamconv/converters/moz.build | 6 +- netwerk/system/mac/moz.build | 13 + netwerk/system/mac/nsNetworkLinkService.h | 54 + netwerk/system/mac/nsNetworkLinkService.mm | 526 +++++++++ netwerk/system/moz.build | 2 + toolkit/components/parentalcontrols/moz.build | 2 + .../nsParentalControlsServiceCocoa.mm | 79 ++ toolkit/components/startup/moz.build | 6 +- toolkit/components/startup/nsUserInfoMac.h | 25 + toolkit/components/startup/nsUserInfoMac.mm | 84 ++ toolkit/library/moz.build | 42 +- toolkit/modules/moz.build | 2 +- toolkit/moz.build | 2 + toolkit/moz.configure | 8 +- toolkit/mozapps/update/updater/Makefile.in | 13 + toolkit/mozapps/update/updater/launchchild_osx.mm | 384 +++++++ .../update/updater/macbuild/Contents/Info.plist.in | 39 + .../update/updater/macbuild/Contents/PkgInfo | 1 + .../Resources/English.lproj/InfoPlist.strings.in | 7 + .../English.lproj/MainMenu.nib/classes.nib | 19 + .../Resources/English.lproj/MainMenu.nib/info.nib | 22 + .../English.lproj/MainMenu.nib/keyedobjects.nib | Bin 0 -> 5567 bytes .../macbuild/Contents/Resources/updater.icns | Bin 0 -> 55969 bytes toolkit/mozapps/update/updater/moz.build | 15 +- toolkit/mozapps/update/updater/progressui_osx.mm | 144 +++ .../mozapps/update/updater/updater-common.build | 18 + toolkit/system/osxproxy/ProxyUtils.h | 21 + toolkit/system/osxproxy/ProxyUtils.mm | 182 +++ toolkit/system/osxproxy/moz.build | 13 + .../system/osxproxy/nsOSXSystemProxySettings.mm | 326 ++++++ .../osxproxy/tests/gtest/TestProxyBypassRules.cpp | 41 + toolkit/system/osxproxy/tests/gtest/moz.build | 17 + toolkit/themes/moz.build | 4 +- .../themes/osx/global/10pct_transparent_grey.png | Bin 0 -> 123 bytes .../themes/osx/global/50pct_transparent_grey.png | Bin 0 -> 107 bytes toolkit/themes/osx/global/alerts/alert.css | 30 + toolkit/themes/osx/global/arrow.css | 38 + toolkit/themes/osx/global/arrow/arrow-dn-dis.gif | Bin 0 -> 65 bytes toolkit/themes/osx/global/arrow/arrow-dn-dis.png | Bin 0 -> 185 bytes toolkit/themes/osx/global/arrow/arrow-dn-sharp.gif | Bin 0 -> 51 bytes toolkit/themes/osx/global/arrow/arrow-dn.gif | Bin 0 -> 56 bytes toolkit/themes/osx/global/arrow/arrow-dn.png | Bin 0 -> 191 bytes toolkit/themes/osx/global/arrow/arrow-lft-dis.gif | Bin 0 -> 105 bytes toolkit/themes/osx/global/arrow/arrow-lft-hov.gif | Bin 0 -> 57 bytes .../osx/global/arrow/arrow-lft-sharp-end.gif | Bin 0 -> 56 bytes .../themes/osx/global/arrow/arrow-lft-sharp.gif | Bin 0 -> 53 bytes toolkit/themes/osx/global/arrow/arrow-lft.gif | Bin 0 -> 57 bytes toolkit/themes/osx/global/arrow/arrow-rit-dis.gif | Bin 0 -> 105 bytes toolkit/themes/osx/global/arrow/arrow-rit-hov.gif | Bin 0 -> 57 bytes .../osx/global/arrow/arrow-rit-sharp-end.gif | Bin 0 -> 56 bytes .../themes/osx/global/arrow/arrow-rit-sharp.gif | Bin 0 -> 53 bytes toolkit/themes/osx/global/arrow/arrow-rit.gif | Bin 0 -> 57 bytes toolkit/themes/osx/global/arrow/arrow-up-dis.gif | Bin 0 -> 65 bytes toolkit/themes/osx/global/arrow/arrow-up-sharp.gif | Bin 0 -> 52 bytes toolkit/themes/osx/global/arrow/arrow-up.gif | Bin 0 -> 56 bytes .../osx/global/arrow/panelarrow-horizontal.png | Bin 0 -> 117 bytes .../osx/global/arrow/panelarrow-horizontal@2x.png | Bin 0 -> 267 bytes .../osx/global/arrow/panelarrow-vertical.png | Bin 0 -> 133 bytes .../osx/global/arrow/panelarrow-vertical@2x.png | Bin 0 -> 227 bytes toolkit/themes/osx/global/autocomplete.css | 174 +++ toolkit/themes/osx/global/button.css | 85 ++ toolkit/themes/osx/global/checkbox.css | 39 + .../themes/osx/global/checkbox/cbox-check-dis.gif | Bin 0 -> 60 bytes toolkit/themes/osx/global/checkbox/cbox-check.gif | Bin 0 -> 54 bytes toolkit/themes/osx/global/colorpicker.css | 41 + toolkit/themes/osx/global/commonDialog.css | 35 + .../osx/global/console/console-error-caret.gif | Bin 0 -> 55 bytes .../osx/global/console/console-error-dash.gif | Bin 0 -> 48 bytes toolkit/themes/osx/global/console/console.css | 165 +++ toolkit/themes/osx/global/customizeToolbar.css | 38 + toolkit/themes/osx/global/datetimepicker.css | 126 ++ toolkit/themes/osx/global/dialog.css | 77 ++ .../themes/osx/global/dirListing/dirListing.css | 104 ++ toolkit/themes/osx/global/dirListing/folder.png | Bin 0 -> 325 bytes toolkit/themes/osx/global/dirListing/remote.png | Bin 0 -> 563 bytes toolkit/themes/osx/global/dirListing/up.png | Bin 0 -> 617 bytes toolkit/themes/osx/global/dropmarker.css | 31 + toolkit/themes/osx/global/filefield.css | 38 + toolkit/themes/osx/global/filters.svg | 14 + toolkit/themes/osx/global/findBar.css | 270 +++++ toolkit/themes/osx/global/global.css | 378 ++++++ toolkit/themes/osx/global/groupbox.css | 30 + toolkit/themes/osx/global/icons/Error.png | Bin 0 -> 1439 bytes .../osx/global/icons/autocomplete-dropmarker.png | Bin 0 -> 234 bytes .../osx/global/icons/autocomplete-search.svg | 22 + toolkit/themes/osx/global/icons/autoscroll.png | Bin 0 -> 2983 bytes toolkit/themes/osx/global/icons/blacklist_64.png | Bin 0 -> 3771 bytes .../themes/osx/global/icons/blacklist_favicon.png | Bin 0 -> 543 bytes toolkit/themes/osx/global/icons/checkbox.png | Bin 0 -> 1737 bytes toolkit/themes/osx/global/icons/checkbox@2x.png | Bin 0 -> 1824 bytes .../themes/osx/global/icons/chevron-inverted.png | Bin 0 -> 247 bytes .../osx/global/icons/chevron-inverted@2x.png | Bin 0 -> 481 bytes toolkit/themes/osx/global/icons/chevron.png | Bin 0 -> 251 bytes toolkit/themes/osx/global/icons/chevron@2x.png | Bin 0 -> 462 bytes toolkit/themes/osx/global/icons/close.png | Bin 0 -> 1240 bytes toolkit/themes/osx/global/icons/close@2x.png | Bin 0 -> 2768 bytes toolkit/themes/osx/global/icons/error-16.png | Bin 0 -> 677 bytes toolkit/themes/osx/global/icons/error-64.png | Bin 0 -> 2533 bytes toolkit/themes/osx/global/icons/error-large.png | Bin 0 -> 1996 bytes toolkit/themes/osx/global/icons/glyph-dropdown.png | Bin 0 -> 99 bytes .../themes/osx/global/icons/glyph-dropdown@2x.png | Bin 0 -> 130 bytes toolkit/themes/osx/global/icons/information-16.png | Bin 0 -> 818 bytes toolkit/themes/osx/global/icons/information-24.png | Bin 0 -> 1289 bytes toolkit/themes/osx/global/icons/information-32.png | Bin 0 -> 1773 bytes toolkit/themes/osx/global/icons/information-64.png | Bin 0 -> 3687 bytes .../themes/osx/global/icons/information-large.png | Bin 0 -> 2592 bytes toolkit/themes/osx/global/icons/loading_16.png | Bin 0 -> 9025 bytes .../osx/global/icons/menulist-dropmarker.png | Bin 0 -> 158 bytes toolkit/themes/osx/global/icons/notfound.png | Bin 0 -> 597 bytes toolkit/themes/osx/global/icons/notloading_16.png | Bin 0 -> 686 bytes .../themes/osx/global/icons/panebutton-active.png | Bin 0 -> 400 bytes .../osx/global/icons/panebutton-inactive.png | Bin 0 -> 257 bytes .../themes/osx/global/icons/panel-dropmarker.png | Bin 0 -> 161 bytes toolkit/themes/osx/global/icons/question-16.png | Bin 0 -> 866 bytes toolkit/themes/osx/global/icons/question-32.png | Bin 0 -> 1962 bytes toolkit/themes/osx/global/icons/question-64.png | Bin 0 -> 3970 bytes toolkit/themes/osx/global/icons/question-large.png | Bin 0 -> 2851 bytes toolkit/themes/osx/global/icons/resizer-rtl.png | Bin 0 -> 192 bytes toolkit/themes/osx/global/icons/resizer-rtl@2x.png | Bin 0 -> 284 bytes toolkit/themes/osx/global/icons/resizer.png | Bin 0 -> 196 bytes toolkit/themes/osx/global/icons/resizer@2x.png | Bin 0 -> 288 bytes toolkit/themes/osx/global/icons/search-textbox.svg | 13 + .../themes/osx/global/icons/searchfield-cancel.svg | 20 + toolkit/themes/osx/global/icons/sslWarning.png | Bin 0 -> 4120 bytes .../osx/global/icons/tabprompts-bgtexture.png | Bin 0 -> 5940 bytes toolkit/themes/osx/global/icons/warning-16.png | Bin 0 -> 690 bytes toolkit/themes/osx/global/icons/warning-32.png | Bin 0 -> 1483 bytes toolkit/themes/osx/global/icons/warning-64.png | Bin 0 -> 3308 bytes toolkit/themes/osx/global/icons/warning-large.png | Bin 0 -> 2281 bytes toolkit/themes/osx/global/in-content/common.css | 121 ++ .../themes/osx/global/in-content/info-pages.css | 1 + toolkit/themes/osx/global/inContentUI.css | 144 +++ toolkit/themes/osx/global/jar.mn | 156 +++ toolkit/themes/osx/global/linkTree.css | 32 + toolkit/themes/osx/global/listbox.css | 113 ++ toolkit/themes/osx/global/menu.css | 187 +++ toolkit/themes/osx/global/menulist.css | 65 ++ toolkit/themes/osx/global/moz.build | 6 + toolkit/themes/osx/global/nativescrollbars.css | 89 ++ toolkit/themes/osx/global/netError.css | 145 +++ toolkit/themes/osx/global/notification.css | 206 ++++ toolkit/themes/osx/global/notification/close.png | Bin 0 -> 795 bytes .../themes/osx/global/notification/error-icon.png | Bin 0 -> 518 bytes .../themes/osx/global/notification/info-icon.png | Bin 0 -> 533 bytes .../osx/global/notification/warning-icon.png | Bin 0 -> 626 bytes toolkit/themes/osx/global/numberbox.css | 33 + toolkit/themes/osx/global/popup.css | 141 +++ toolkit/themes/osx/global/preferences.css | 64 ++ toolkit/themes/osx/global/progressmeter.css | 22 + toolkit/themes/osx/global/radio.css | 43 + toolkit/themes/osx/global/resizer.css | 69 ++ toolkit/themes/osx/global/richlistbox.css | 27 + toolkit/themes/osx/global/scale.css | 46 + .../themes/osx/global/scale/scale-tray-horiz.gif | Bin 0 -> 50 bytes .../themes/osx/global/scale/scale-tray-vert.gif | Bin 0 -> 50 bytes toolkit/themes/osx/global/scrollbox.css | 62 + toolkit/themes/osx/global/shared.inc | 20 + toolkit/themes/osx/global/spinbuttons.css | 31 + toolkit/themes/osx/global/splitter.css | 124 ++ toolkit/themes/osx/global/splitter/dimple.png | Bin 0 -> 155 bytes toolkit/themes/osx/global/splitter/grip-bottom.gif | Bin 0 -> 145 bytes toolkit/themes/osx/global/splitter/grip-left.gif | Bin 0 -> 157 bytes toolkit/themes/osx/global/splitter/grip-right.gif | Bin 0 -> 157 bytes toolkit/themes/osx/global/splitter/grip-top.gif | Bin 0 -> 144 bytes toolkit/themes/osx/global/tabbox.css | 148 +++ toolkit/themes/osx/global/tabprompts.css | 67 ++ toolkit/themes/osx/global/textbox.css | 102 ++ toolkit/themes/osx/global/toolbar.css | 127 +++ toolkit/themes/osx/global/toolbar/spring.png | Bin 0 -> 239 bytes .../osx/global/toolbar/toolbar-separator.png | Bin 0 -> 115 bytes toolkit/themes/osx/global/toolbarbutton.css | 124 ++ toolkit/themes/osx/global/tree.css | 296 +++++ .../themes/osx/global/tree/arrow-disclosure.svg | 28 + toolkit/themes/osx/global/tree/columnpicker.gif | Bin 0 -> 68 bytes toolkit/themes/osx/global/tree/folder.png | Bin 0 -> 320 bytes toolkit/themes/osx/global/tree/folder@2x.png | Bin 0 -> 589 bytes toolkit/themes/osx/global/viewbuttons.css | 36 + toolkit/themes/osx/global/wizard.css | 62 + toolkit/themes/osx/mochitests/.eslintrc.js | 7 + toolkit/themes/osx/mochitests/chrome.ini | 3 + toolkit/themes/osx/mochitests/test_bug510426.xul | 54 + toolkit/themes/osx/moz.build | 8 + toolkit/themes/osx/mozapps/downloads/buttons.png | Bin 0 -> 2288 bytes .../themes/osx/mozapps/downloads/downloadIcon.png | Bin 0 -> 1301 bytes toolkit/themes/osx/mozapps/downloads/downloads.css | 123 ++ .../osx/mozapps/downloads/unknownContentType.css | 30 + toolkit/themes/osx/mozapps/extensions/about.css | 78 ++ .../osx/mozapps/extensions/alerticon-error.png | Bin 0 -> 3402 bytes .../mozapps/extensions/alerticon-info-negative.png | Bin 0 -> 1564 bytes .../mozapps/extensions/alerticon-info-positive.png | Bin 0 -> 1338 bytes .../osx/mozapps/extensions/alerticon-warning.png | Bin 0 -> 1567 bytes .../themes/osx/mozapps/extensions/blocklist.css | 20 + toolkit/themes/osx/mozapps/extensions/cancel.png | Bin 0 -> 115 bytes .../osx/mozapps/extensions/category-available.png | Bin 0 -> 1671 bytes .../mozapps/extensions/category-dictionaries.png | Bin 0 -> 1769 bytes .../osx/mozapps/extensions/category-discover.png | Bin 0 -> 1324 bytes .../mozapps/extensions/category-experiments.png | Bin 0 -> 822 bytes .../osx/mozapps/extensions/category-plugins.png | Bin 0 -> 886 bytes .../osx/mozapps/extensions/category-recent.png | Bin 0 -> 1642 bytes .../osx/mozapps/extensions/category-search.png | Bin 0 -> 2600 bytes .../mozapps/extensions/category-searchengines.png | Bin 0 -> 2814 bytes .../osx/mozapps/extensions/category-service.png | Bin 0 -> 2063 bytes .../mozapps/extensions/dictionaryGeneric-16.png | Bin 0 -> 742 bytes .../osx/mozapps/extensions/dictionaryGeneric.png | Bin 0 -> 1769 bytes .../osx/mozapps/extensions/discover-logo.png | Bin 0 -> 12007 bytes toolkit/themes/osx/mozapps/extensions/eula.css | 47 + .../osx/mozapps/extensions/experimentGeneric.png | Bin 0 -> 822 bytes .../osx/mozapps/extensions/extensionGeneric-16.png | Bin 0 -> 554 bytes .../osx/mozapps/extensions/extensionGeneric.png | Bin 0 -> 1302 bytes .../themes/osx/mozapps/extensions/extensions.css | 1206 ++++++++++++++++++++ toolkit/themes/osx/mozapps/extensions/heart.png | Bin 0 -> 2949 bytes .../osx/mozapps/extensions/localeGeneric.png | Bin 0 -> 2410 bytes .../themes/osx/mozapps/extensions/navigation.png | Bin 0 -> 586 bytes toolkit/themes/osx/mozapps/extensions/newaddon.css | 112 ++ .../osx/mozapps/extensions/rating-not-won.png | Bin 0 -> 1559 bytes .../themes/osx/mozapps/extensions/rating-won.png | Bin 0 -> 1662 bytes toolkit/themes/osx/mozapps/extensions/search.png | Bin 0 -> 423 bytes .../themes/osx/mozapps/extensions/selectAddons.css | 163 +++ .../mozapps/extensions/stripes-compatibility.png | Bin 0 -> 1041 bytes .../osx/mozapps/extensions/stripes-error.png | Bin 0 -> 1979 bytes .../mozapps/extensions/stripes-info-negative.png | Bin 0 -> 2027 bytes .../mozapps/extensions/stripes-info-positive.png | Bin 0 -> 1852 bytes .../osx/mozapps/extensions/stripes-warning.png | Bin 0 -> 2177 bytes .../osx/mozapps/extensions/themeGeneric-16.png | Bin 0 -> 710 bytes .../themes/osx/mozapps/extensions/themeGeneric.png | Bin 0 -> 2185 bytes .../extensions/toolbarbutton-dropmarker.png | Bin 0 -> 147 bytes toolkit/themes/osx/mozapps/extensions/update.css | 26 + .../osx/mozapps/extensions/xpinstallConfirm.css | 90 ++ toolkit/themes/osx/mozapps/handling/handling.css | 30 + toolkit/themes/osx/mozapps/jar.mn | 79 ++ toolkit/themes/osx/mozapps/moz.build | 6 + toolkit/themes/osx/mozapps/passwordmgr/key-16.png | Bin 0 -> 773 bytes toolkit/themes/osx/mozapps/passwordmgr/key-64.png | Bin 0 -> 6142 bytes toolkit/themes/osx/mozapps/passwordmgr/key.png | Bin 0 -> 658 bytes .../osx/mozapps/plugins/notifyPluginGeneric.png | Bin 0 -> 313 bytes .../osx/mozapps/plugins/pluginBlocked-64.png | Bin 0 -> 4563 bytes .../themes/osx/mozapps/plugins/pluginBlocked.png | Bin 0 -> 2152 bytes .../osx/mozapps/plugins/pluginGeneric-16.png | Bin 0 -> 759 bytes .../themes/osx/mozapps/plugins/pluginGeneric.png | Bin 0 -> 1939 bytes .../themes/osx/mozapps/plugins/pluginHelp-16.png | Bin 0 -> 620 bytes .../osx/mozapps/profile/profileSelection.css | 29 + .../osx/mozapps/profile/profileicon-selected.png | Bin 0 -> 502 bytes toolkit/themes/osx/mozapps/profile/profileicon.png | Bin 0 -> 588 bytes toolkit/themes/osx/mozapps/update/buttons.png | Bin 0 -> 2288 bytes toolkit/themes/osx/mozapps/update/updates.css | 171 +++ .../themes/osx/mozapps/viewsource/viewsource.css | 5 + toolkit/themes/osx/reftests/482681-ref.xul | 21 + toolkit/themes/osx/reftests/482681.xul | 22 + toolkit/themes/osx/reftests/baseline.xul | 175 +++ toolkit/themes/osx/reftests/checkboxsize-ref.xul | 32 + toolkit/themes/osx/reftests/checkboxsize.xul | 31 + toolkit/themes/osx/reftests/nostretch-ref.xul | 107 ++ toolkit/themes/osx/reftests/nostretch.xul | 120 ++ toolkit/themes/osx/reftests/radiosize-ref.xul | 32 + toolkit/themes/osx/reftests/radiosize.xul | 31 + toolkit/themes/osx/reftests/reftest-stylo.list | 6 + toolkit/themes/osx/reftests/reftest.list | 5 + toolkit/xre/MacApplicationDelegate.h | 16 + toolkit/xre/MacApplicationDelegate.mm | 396 +++++++ toolkit/xre/MacAutoreleasePool.h | 31 + toolkit/xre/MacAutoreleasePool.mm | 20 + toolkit/xre/MacLaunchHelper.h | 23 + toolkit/xre/MacLaunchHelper.mm | 137 +++ toolkit/xre/moz.build | 15 + uriloader/exthandler/mac/nsDecodeAppleFile.cpp | 389 +++++++ uriloader/exthandler/mac/nsDecodeAppleFile.h | 118 ++ uriloader/exthandler/mac/nsLocalHandlerAppMac.h | 26 + uriloader/exthandler/mac/nsLocalHandlerAppMac.mm | 84 ++ uriloader/exthandler/mac/nsMIMEInfoMac.h | 34 + uriloader/exthandler/mac/nsMIMEInfoMac.mm | 114 ++ uriloader/exthandler/mac/nsOSHelperAppService.h | 48 + uriloader/exthandler/mac/nsOSHelperAppService.mm | 569 +++++++++ uriloader/exthandler/moz.build | 10 +- xpcom/build/moz.build | 3 + 381 files changed, 22780 insertions(+), 36 deletions(-) create mode 100644 accessible/mac/ARIAGridAccessibleWrap.h create mode 100644 accessible/mac/AccessibleWrap.h create mode 100644 accessible/mac/AccessibleWrap.mm create mode 100644 accessible/mac/ApplicationAccessibleWrap.h create mode 100644 accessible/mac/DocAccessibleWrap.h create mode 100644 accessible/mac/DocAccessibleWrap.mm create mode 100644 accessible/mac/HTMLTableAccessibleWrap.h create mode 100644 accessible/mac/HyperTextAccessibleWrap.h create mode 100644 accessible/mac/ImageAccessibleWrap.h create mode 100644 accessible/mac/MacUtils.h create mode 100644 accessible/mac/MacUtils.mm create mode 100644 accessible/mac/Platform.mm create mode 100644 accessible/mac/RootAccessibleWrap.h create mode 100644 accessible/mac/RootAccessibleWrap.mm create mode 100644 accessible/mac/TextLeafAccessibleWrap.h create mode 100644 accessible/mac/XULListboxAccessibleWrap.h create mode 100644 accessible/mac/XULMenuAccessibleWrap.h create mode 100644 accessible/mac/XULTreeGridAccessibleWrap.h create mode 100644 accessible/mac/moz.build create mode 100644 accessible/mac/mozAccessible.h create mode 100644 accessible/mac/mozAccessible.mm create mode 100644 accessible/mac/mozAccessibleProtocol.h create mode 100644 accessible/mac/mozActionElements.h create mode 100644 accessible/mac/mozActionElements.mm create mode 100644 accessible/mac/mozDocAccessible.h create mode 100644 accessible/mac/mozDocAccessible.mm create mode 100644 accessible/mac/mozHTMLAccessible.h create mode 100644 accessible/mac/mozHTMLAccessible.mm create mode 100644 accessible/mac/mozTableAccessible.h create mode 100644 accessible/mac/mozTableAccessible.mm create mode 100644 accessible/mac/mozTextAccessible.h create mode 100644 accessible/mac/mozTextAccessible.mm create mode 100644 embedding/components/printingui/mac/moz.build create mode 100644 embedding/components/printingui/mac/nsPrintProgress.cpp create mode 100644 embedding/components/printingui/mac/nsPrintProgress.h create mode 100644 embedding/components/printingui/mac/nsPrintProgressParams.cpp create mode 100644 embedding/components/printingui/mac/nsPrintProgressParams.h create mode 100644 embedding/components/printingui/mac/nsPrintingPromptService.h create mode 100644 embedding/components/printingui/mac/nsPrintingPromptServiceX.mm create mode 100644 gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp create mode 100644 gfx/layers/basic/MacIOSurfaceTextureHostBasic.h create mode 100644 gfx/layers/ipc/ShadowLayerUtilsMac.cpp create mode 100644 gfx/layers/opengl/GLManager.cpp create mode 100644 gfx/layers/opengl/GLManager.h create mode 100644 gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp create mode 100644 gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h create mode 100644 gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp create mode 100644 gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h create mode 100644 image/decoders/icon/mac/moz.build create mode 100644 image/decoders/icon/mac/nsIconChannel.h create mode 100644 image/decoders/icon/mac/nsIconChannelCocoa.mm create mode 100644 intl/locale/mac/moz.build create mode 100644 intl/locale/mac/nsCollationMacUC.cpp create mode 100644 intl/locale/mac/nsCollationMacUC.h create mode 100644 intl/locale/mac/nsDateTimeFormatMac.cpp create mode 100644 intl/locale/mac/nsDateTimeFormatMac.h create mode 100644 intl/locale/mac/nsMacCharset.cpp create mode 100644 intl/lwbrk/nsCarbonBreaker.cpp create mode 100644 js/xpconnect/shell/xpcshellMacUtils.h create mode 100644 js/xpconnect/shell/xpcshellMacUtils.mm create mode 100644 mailnews/base/src/nsMessengerOSXIntegration.h create mode 100644 mailnews/base/src/nsMessengerOSXIntegration.mm create mode 100644 mailnews/compose/src/nsMsgAppleCodes.h create mode 100644 mailnews/compose/src/nsMsgAppleDouble.h create mode 100644 mailnews/compose/src/nsMsgAppleDoubleEncode.cpp create mode 100644 mailnews/compose/src/nsMsgAppleEncode.cpp create mode 100644 media/libcubeb/src/cubeb_osx_run_loop.c create mode 100644 media/libcubeb/src/cubeb_osx_run_loop.h create mode 100644 netwerk/base/NetworkInfoServiceCocoa.cpp create mode 100644 netwerk/base/nsURLHelperOSX.cpp create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderOperator.h create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp create mode 100644 netwerk/dns/mdns/libmdns/MDNSResponderReply.h create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp create mode 100644 netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h create mode 100644 netwerk/system/mac/moz.build create mode 100644 netwerk/system/mac/nsNetworkLinkService.h create mode 100644 netwerk/system/mac/nsNetworkLinkService.mm create mode 100644 toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm create mode 100644 toolkit/components/startup/nsUserInfoMac.h create mode 100644 toolkit/components/startup/nsUserInfoMac.mm create mode 100644 toolkit/mozapps/update/updater/launchchild_osx.mm create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Info.plist.in create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib create mode 100644 toolkit/mozapps/update/updater/macbuild/Contents/Resources/updater.icns create mode 100644 toolkit/mozapps/update/updater/progressui_osx.mm create mode 100644 toolkit/system/osxproxy/ProxyUtils.h create mode 100644 toolkit/system/osxproxy/ProxyUtils.mm create mode 100644 toolkit/system/osxproxy/moz.build create mode 100644 toolkit/system/osxproxy/nsOSXSystemProxySettings.mm create mode 100644 toolkit/system/osxproxy/tests/gtest/TestProxyBypassRules.cpp create mode 100644 toolkit/system/osxproxy/tests/gtest/moz.build create mode 100644 toolkit/themes/osx/global/10pct_transparent_grey.png create mode 100644 toolkit/themes/osx/global/50pct_transparent_grey.png create mode 100644 toolkit/themes/osx/global/alerts/alert.css create mode 100644 toolkit/themes/osx/global/arrow.css create mode 100644 toolkit/themes/osx/global/arrow/arrow-dn-dis.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-dn-dis.png create mode 100644 toolkit/themes/osx/global/arrow/arrow-dn-sharp.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-dn.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-dn.png create mode 100644 toolkit/themes/osx/global/arrow/arrow-lft-dis.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-lft-hov.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-lft-sharp-end.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-lft-sharp.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-lft.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-rit-dis.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-rit-hov.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-rit-sharp-end.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-rit-sharp.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-rit.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-up-dis.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-up-sharp.gif create mode 100644 toolkit/themes/osx/global/arrow/arrow-up.gif create mode 100644 toolkit/themes/osx/global/arrow/panelarrow-horizontal.png create mode 100644 toolkit/themes/osx/global/arrow/panelarrow-horizontal@2x.png create mode 100644 toolkit/themes/osx/global/arrow/panelarrow-vertical.png create mode 100644 toolkit/themes/osx/global/arrow/panelarrow-vertical@2x.png create mode 100644 toolkit/themes/osx/global/autocomplete.css create mode 100644 toolkit/themes/osx/global/button.css create mode 100644 toolkit/themes/osx/global/checkbox.css create mode 100644 toolkit/themes/osx/global/checkbox/cbox-check-dis.gif create mode 100644 toolkit/themes/osx/global/checkbox/cbox-check.gif create mode 100644 toolkit/themes/osx/global/colorpicker.css create mode 100644 toolkit/themes/osx/global/commonDialog.css create mode 100644 toolkit/themes/osx/global/console/console-error-caret.gif create mode 100644 toolkit/themes/osx/global/console/console-error-dash.gif create mode 100644 toolkit/themes/osx/global/console/console.css create mode 100644 toolkit/themes/osx/global/customizeToolbar.css create mode 100644 toolkit/themes/osx/global/datetimepicker.css create mode 100644 toolkit/themes/osx/global/dialog.css create mode 100644 toolkit/themes/osx/global/dirListing/dirListing.css create mode 100644 toolkit/themes/osx/global/dirListing/folder.png create mode 100644 toolkit/themes/osx/global/dirListing/remote.png create mode 100644 toolkit/themes/osx/global/dirListing/up.png create mode 100644 toolkit/themes/osx/global/dropmarker.css create mode 100644 toolkit/themes/osx/global/filefield.css create mode 100644 toolkit/themes/osx/global/filters.svg create mode 100644 toolkit/themes/osx/global/findBar.css create mode 100644 toolkit/themes/osx/global/global.css create mode 100644 toolkit/themes/osx/global/groupbox.css create mode 100644 toolkit/themes/osx/global/icons/Error.png create mode 100644 toolkit/themes/osx/global/icons/autocomplete-dropmarker.png create mode 100644 toolkit/themes/osx/global/icons/autocomplete-search.svg create mode 100644 toolkit/themes/osx/global/icons/autoscroll.png create mode 100644 toolkit/themes/osx/global/icons/blacklist_64.png create mode 100644 toolkit/themes/osx/global/icons/blacklist_favicon.png create mode 100644 toolkit/themes/osx/global/icons/checkbox.png create mode 100644 toolkit/themes/osx/global/icons/checkbox@2x.png create mode 100644 toolkit/themes/osx/global/icons/chevron-inverted.png create mode 100644 toolkit/themes/osx/global/icons/chevron-inverted@2x.png create mode 100644 toolkit/themes/osx/global/icons/chevron.png create mode 100644 toolkit/themes/osx/global/icons/chevron@2x.png create mode 100644 toolkit/themes/osx/global/icons/close.png create mode 100755 toolkit/themes/osx/global/icons/close@2x.png create mode 100644 toolkit/themes/osx/global/icons/error-16.png create mode 100644 toolkit/themes/osx/global/icons/error-64.png create mode 100644 toolkit/themes/osx/global/icons/error-large.png create mode 100644 toolkit/themes/osx/global/icons/glyph-dropdown.png create mode 100644 toolkit/themes/osx/global/icons/glyph-dropdown@2x.png create mode 100644 toolkit/themes/osx/global/icons/information-16.png create mode 100644 toolkit/themes/osx/global/icons/information-24.png create mode 100644 toolkit/themes/osx/global/icons/information-32.png create mode 100644 toolkit/themes/osx/global/icons/information-64.png create mode 100644 toolkit/themes/osx/global/icons/information-large.png create mode 100644 toolkit/themes/osx/global/icons/loading_16.png create mode 100644 toolkit/themes/osx/global/icons/menulist-dropmarker.png create mode 100644 toolkit/themes/osx/global/icons/notfound.png create mode 100644 toolkit/themes/osx/global/icons/notloading_16.png create mode 100644 toolkit/themes/osx/global/icons/panebutton-active.png create mode 100644 toolkit/themes/osx/global/icons/panebutton-inactive.png create mode 100644 toolkit/themes/osx/global/icons/panel-dropmarker.png create mode 100644 toolkit/themes/osx/global/icons/question-16.png create mode 100644 toolkit/themes/osx/global/icons/question-32.png create mode 100644 toolkit/themes/osx/global/icons/question-64.png create mode 100644 toolkit/themes/osx/global/icons/question-large.png create mode 100644 toolkit/themes/osx/global/icons/resizer-rtl.png create mode 100644 toolkit/themes/osx/global/icons/resizer-rtl@2x.png create mode 100644 toolkit/themes/osx/global/icons/resizer.png create mode 100644 toolkit/themes/osx/global/icons/resizer@2x.png create mode 100644 toolkit/themes/osx/global/icons/search-textbox.svg create mode 100644 toolkit/themes/osx/global/icons/searchfield-cancel.svg create mode 100644 toolkit/themes/osx/global/icons/sslWarning.png create mode 100644 toolkit/themes/osx/global/icons/tabprompts-bgtexture.png create mode 100644 toolkit/themes/osx/global/icons/warning-16.png create mode 100644 toolkit/themes/osx/global/icons/warning-32.png create mode 100644 toolkit/themes/osx/global/icons/warning-64.png create mode 100644 toolkit/themes/osx/global/icons/warning-large.png create mode 100644 toolkit/themes/osx/global/in-content/common.css create mode 100644 toolkit/themes/osx/global/in-content/info-pages.css create mode 100644 toolkit/themes/osx/global/inContentUI.css create mode 100644 toolkit/themes/osx/global/jar.mn create mode 100644 toolkit/themes/osx/global/linkTree.css create mode 100644 toolkit/themes/osx/global/listbox.css create mode 100644 toolkit/themes/osx/global/menu.css create mode 100644 toolkit/themes/osx/global/menulist.css create mode 100644 toolkit/themes/osx/global/moz.build create mode 100644 toolkit/themes/osx/global/nativescrollbars.css create mode 100644 toolkit/themes/osx/global/netError.css create mode 100644 toolkit/themes/osx/global/notification.css create mode 100644 toolkit/themes/osx/global/notification/close.png create mode 100644 toolkit/themes/osx/global/notification/error-icon.png create mode 100644 toolkit/themes/osx/global/notification/info-icon.png create mode 100644 toolkit/themes/osx/global/notification/warning-icon.png create mode 100644 toolkit/themes/osx/global/numberbox.css create mode 100644 toolkit/themes/osx/global/popup.css create mode 100644 toolkit/themes/osx/global/preferences.css create mode 100644 toolkit/themes/osx/global/progressmeter.css create mode 100644 toolkit/themes/osx/global/radio.css create mode 100644 toolkit/themes/osx/global/resizer.css create mode 100644 toolkit/themes/osx/global/richlistbox.css create mode 100644 toolkit/themes/osx/global/scale.css create mode 100644 toolkit/themes/osx/global/scale/scale-tray-horiz.gif create mode 100644 toolkit/themes/osx/global/scale/scale-tray-vert.gif create mode 100644 toolkit/themes/osx/global/scrollbox.css create mode 100644 toolkit/themes/osx/global/shared.inc create mode 100644 toolkit/themes/osx/global/spinbuttons.css create mode 100644 toolkit/themes/osx/global/splitter.css create mode 100644 toolkit/themes/osx/global/splitter/dimple.png create mode 100644 toolkit/themes/osx/global/splitter/grip-bottom.gif create mode 100644 toolkit/themes/osx/global/splitter/grip-left.gif create mode 100644 toolkit/themes/osx/global/splitter/grip-right.gif create mode 100644 toolkit/themes/osx/global/splitter/grip-top.gif create mode 100644 toolkit/themes/osx/global/tabbox.css create mode 100644 toolkit/themes/osx/global/tabprompts.css create mode 100644 toolkit/themes/osx/global/textbox.css create mode 100644 toolkit/themes/osx/global/toolbar.css create mode 100644 toolkit/themes/osx/global/toolbar/spring.png create mode 100644 toolkit/themes/osx/global/toolbar/toolbar-separator.png create mode 100644 toolkit/themes/osx/global/toolbarbutton.css create mode 100644 toolkit/themes/osx/global/tree.css create mode 100644 toolkit/themes/osx/global/tree/arrow-disclosure.svg create mode 100644 toolkit/themes/osx/global/tree/columnpicker.gif create mode 100644 toolkit/themes/osx/global/tree/folder.png create mode 100644 toolkit/themes/osx/global/tree/folder@2x.png create mode 100644 toolkit/themes/osx/global/viewbuttons.css create mode 100644 toolkit/themes/osx/global/wizard.css create mode 100644 toolkit/themes/osx/mochitests/.eslintrc.js create mode 100644 toolkit/themes/osx/mochitests/chrome.ini create mode 100644 toolkit/themes/osx/mochitests/test_bug510426.xul create mode 100644 toolkit/themes/osx/moz.build create mode 100644 toolkit/themes/osx/mozapps/downloads/buttons.png create mode 100644 toolkit/themes/osx/mozapps/downloads/downloadIcon.png create mode 100644 toolkit/themes/osx/mozapps/downloads/downloads.css create mode 100644 toolkit/themes/osx/mozapps/downloads/unknownContentType.css create mode 100644 toolkit/themes/osx/mozapps/extensions/about.css create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-error.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-warning.png create mode 100644 toolkit/themes/osx/mozapps/extensions/blocklist.css create mode 100644 toolkit/themes/osx/mozapps/extensions/cancel.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-available.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-dictionaries.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-discover.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-experiments.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-plugins.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-recent.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-search.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-searchengines.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-service.png create mode 100644 toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/discover-logo.png create mode 100644 toolkit/themes/osx/mozapps/extensions/eula.css create mode 100644 toolkit/themes/osx/mozapps/extensions/experimentGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensionGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensions.css create mode 100644 toolkit/themes/osx/mozapps/extensions/heart.png create mode 100644 toolkit/themes/osx/mozapps/extensions/localeGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/navigation.png create mode 100644 toolkit/themes/osx/mozapps/extensions/newaddon.css create mode 100644 toolkit/themes/osx/mozapps/extensions/rating-not-won.png create mode 100644 toolkit/themes/osx/mozapps/extensions/rating-won.png create mode 100644 toolkit/themes/osx/mozapps/extensions/search.png create mode 100644 toolkit/themes/osx/mozapps/extensions/selectAddons.css create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-compatibility.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-error.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-warning.png create mode 100644 toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/themeGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png create mode 100644 toolkit/themes/osx/mozapps/extensions/update.css create mode 100644 toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css create mode 100644 toolkit/themes/osx/mozapps/handling/handling.css create mode 100644 toolkit/themes/osx/mozapps/jar.mn create mode 100644 toolkit/themes/osx/mozapps/moz.build create mode 100644 toolkit/themes/osx/mozapps/passwordmgr/key-16.png create mode 100644 toolkit/themes/osx/mozapps/passwordmgr/key-64.png create mode 100644 toolkit/themes/osx/mozapps/passwordmgr/key.png create mode 100644 toolkit/themes/osx/mozapps/plugins/notifyPluginGeneric.png create mode 100644 toolkit/themes/osx/mozapps/plugins/pluginBlocked-64.png create mode 100644 toolkit/themes/osx/mozapps/plugins/pluginBlocked.png create mode 100644 toolkit/themes/osx/mozapps/plugins/pluginGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/plugins/pluginGeneric.png create mode 100644 toolkit/themes/osx/mozapps/plugins/pluginHelp-16.png create mode 100644 toolkit/themes/osx/mozapps/profile/profileSelection.css create mode 100644 toolkit/themes/osx/mozapps/profile/profileicon-selected.png create mode 100644 toolkit/themes/osx/mozapps/profile/profileicon.png create mode 100644 toolkit/themes/osx/mozapps/update/buttons.png create mode 100644 toolkit/themes/osx/mozapps/update/updates.css create mode 100644 toolkit/themes/osx/mozapps/viewsource/viewsource.css create mode 100644 toolkit/themes/osx/reftests/482681-ref.xul create mode 100644 toolkit/themes/osx/reftests/482681.xul create mode 100644 toolkit/themes/osx/reftests/baseline.xul create mode 100644 toolkit/themes/osx/reftests/checkboxsize-ref.xul create mode 100644 toolkit/themes/osx/reftests/checkboxsize.xul create mode 100644 toolkit/themes/osx/reftests/nostretch-ref.xul create mode 100644 toolkit/themes/osx/reftests/nostretch.xul create mode 100644 toolkit/themes/osx/reftests/radiosize-ref.xul create mode 100644 toolkit/themes/osx/reftests/radiosize.xul create mode 100644 toolkit/themes/osx/reftests/reftest-stylo.list create mode 100644 toolkit/themes/osx/reftests/reftest.list create mode 100644 toolkit/xre/MacApplicationDelegate.h create mode 100644 toolkit/xre/MacApplicationDelegate.mm create mode 100644 toolkit/xre/MacAutoreleasePool.h create mode 100644 toolkit/xre/MacAutoreleasePool.mm create mode 100644 toolkit/xre/MacLaunchHelper.h create mode 100644 toolkit/xre/MacLaunchHelper.mm create mode 100644 uriloader/exthandler/mac/nsDecodeAppleFile.cpp create mode 100644 uriloader/exthandler/mac/nsDecodeAppleFile.h create mode 100644 uriloader/exthandler/mac/nsLocalHandlerAppMac.h create mode 100644 uriloader/exthandler/mac/nsLocalHandlerAppMac.mm create mode 100644 uriloader/exthandler/mac/nsMIMEInfoMac.h create mode 100644 uriloader/exthandler/mac/nsMIMEInfoMac.mm create mode 100644 uriloader/exthandler/mac/nsOSHelperAppService.h create mode 100644 uriloader/exthandler/mac/nsOSHelperAppService.mm diff --git a/accessible/base/moz.build b/accessible/base/moz.build index 54627ca50c..ea9b67aee9 100644 --- a/accessible/base/moz.build +++ b/accessible/base/moz.build @@ -96,6 +96,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': '/accessible/windows/ia2', '/accessible/windows/msaa', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/generic/moz.build b/accessible/generic/moz.build index 720d9bf01b..6855daf909 100644 --- a/accessible/generic/moz.build +++ b/accessible/generic/moz.build @@ -52,6 +52,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': '/accessible/windows/ia2', '/accessible/windows/msaa', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/html/moz.build b/accessible/html/moz.build index a18c4e59b1..e486f10456 100644 --- a/accessible/html/moz.build +++ b/accessible/html/moz.build @@ -32,6 +32,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': '/accessible/windows/ia2', '/accessible/windows/msaa', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/ipc/moz.build b/accessible/ipc/moz.build index 91fd1fa4d3..cb852de271 100644 --- a/accessible/ipc/moz.build +++ b/accessible/ipc/moz.build @@ -19,6 +19,10 @@ else: LOCAL_INCLUDES += [ '/accessible/atk', ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/ipc/other/moz.build b/accessible/ipc/other/moz.build index 489520cef6..50f96de040 100644 --- a/accessible/ipc/other/moz.build +++ b/accessible/ipc/other/moz.build @@ -28,6 +28,10 @@ if CONFIG['ACCESSIBILITY']: LOCAL_INCLUDES += [ '/accessible/atk', ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/mac/ARIAGridAccessibleWrap.h b/accessible/mac/ARIAGridAccessibleWrap.h new file mode 100644 index 0000000000..5d397e915c --- /dev/null +++ b/accessible/mac/ARIAGridAccessibleWrap.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H +#define MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H + +#include "ARIAGridAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class ARIAGridAccessible ARIAGridAccessibleWrap; +typedef class ARIAGridCellAccessible ARIAGridCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/AccessibleWrap.h b/accessible/mac/AccessibleWrap.h new file mode 100644 index 0000000000..6c746ff0dc --- /dev/null +++ b/accessible/mac/AccessibleWrap.h @@ -0,0 +1,103 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* For documentation of the accessibility architecture, + * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html + */ + +#ifndef _AccessibleWrap_H_ +#define _AccessibleWrap_H_ + +#include + +#include "Accessible.h" +#include "States.h" + +#include "nsCOMPtr.h" + +#include "nsTArray.h" + +#if defined(__OBJC__) +@class mozAccessible; +#endif + +namespace mozilla { +namespace a11y { + +class AccessibleWrap : public Accessible +{ +public: // construction, destruction + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc); + virtual ~AccessibleWrap(); + + /** + * Get the native Obj-C object (mozAccessible). + */ + virtual void GetNativeInterface(void** aOutAccessible) override; + + /** + * The objective-c |Class| type that this accessible's native object + * should be instantied with. used on runtime to determine the + * right type for this accessible's associated native object. + */ + virtual Class GetNativeType (); + + virtual void Shutdown () override; + + virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override; + virtual bool RemoveChild(Accessible* aAccessible) override; + + virtual nsresult HandleAccEvent(AccEvent* aEvent) override; + +protected: + + /** + * Return true if the parent doesn't have children to expose to AT. + */ + bool AncestorIsFlat(); + + /** + * Get the native object. Create it if needed. + */ +#if defined(__OBJC__) + mozAccessible* GetNativeObject(); +#else + id GetNativeObject(); +#endif + +private: + + /** + * Our native object. Private because its creation is done lazily. + * Don't access it directly. Ever. Unless you are GetNativeObject() or + * Shutdown() + */ +#if defined(__OBJC__) + // if we are in Objective-C, we use the actual Obj-C class. + mozAccessible* mNativeObject; +#else + id mNativeObject; +#endif + + /** + * We have created our native. This does not mean there is one. + * This can never go back to false. + * We need it because checking whether we need a native object cost time. + */ + bool mNativeInited; +}; + +#if defined(__OBJC__) + void FireNativeEvent(mozAccessible* aNativeAcc, uint32_t aEventType); +#else + void FireNativeEvent(id aNativeAcc, uint32_t aEventType); +#endif + +Class GetTypeFromRole(roles::Role aRole); + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/AccessibleWrap.mm b/accessible/mac/AccessibleWrap.mm new file mode 100644 index 0000000000..65f2e1db42 --- /dev/null +++ b/accessible/mac/AccessibleWrap.mm @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DocAccessible.h" +#include "nsObjCExceptions.h" + +#include "Accessible-inl.h" +#include "nsAccUtils.h" +#include "Role.h" + +#import "mozAccessible.h" +#import "mozActionElements.h" +#import "mozHTMLAccessible.h" +#import "mozTableAccessible.h" +#import "mozTextAccessible.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +AccessibleWrap:: + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : + Accessible(aContent, aDoc), mNativeObject(nil), + mNativeInited(false) +{ +} + +AccessibleWrap::~AccessibleWrap() +{ +} + +mozAccessible* +AccessibleWrap::GetNativeObject() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (!mNativeInited && !mNativeObject && !IsDefunct() && !AncestorIsFlat()) { + uintptr_t accWrap = reinterpret_cast(this); + mNativeObject = [[GetNativeType() alloc] initWithAccessible:accWrap]; + } + + mNativeInited = true; + + return mNativeObject; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +void +AccessibleWrap::GetNativeInterface(void** aOutInterface) +{ + *aOutInterface = static_cast(GetNativeObject()); +} + +// overridden in subclasses to create the right kind of object. by default we create a generic +// 'mozAccessible' node. +Class +AccessibleWrap::GetNativeType () +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (IsXULTabpanels()) + return [mozPaneAccessible class]; + + if (IsTable()) + return [mozTableAccessible class]; + + if (IsTableRow()) + return [mozTableRowAccessible class]; + + if (IsTableCell()) + return [mozTableCellAccessible class]; + + return GetTypeFromRole(Role()); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +// this method is very important. it is fired when an accessible object "dies". after this point +// the object might still be around (because some 3rd party still has a ref to it), but it is +// in fact 'dead'. +void +AccessibleWrap::Shutdown () +{ + // this ensure we will not try to re-create the native object. + mNativeInited = true; + + // we really intend to access the member directly. + if (mNativeObject) { + [mNativeObject expire]; + [mNativeObject release]; + mNativeObject = nil; + } + + Accessible::Shutdown(); +} + +nsresult +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + nsresult rv = Accessible::HandleAccEvent(aEvent); + NS_ENSURE_SUCCESS(rv, rv); + + if (IPCAccessibilityActive()) { + return NS_OK; + } + + uint32_t eventType = aEvent->GetEventType(); + + // ignore everything but focus-changed, value-changed, caret, selection + // and document load complete events for now. + if (eventType != nsIAccessibleEvent::EVENT_FOCUS && + eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && + eventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE && + eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && + eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED && + eventType != nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) + return NS_OK; + + Accessible* accessible = aEvent->GetAccessible(); + NS_ENSURE_STATE(accessible); + + mozAccessible *nativeAcc = nil; + accessible->GetNativeInterface((void**)&nativeAcc); + if (!nativeAcc) + return NS_ERROR_FAILURE; + + FireNativeEvent(nativeAcc, eventType); + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +bool +AccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) +{ + bool inserted = Accessible::InsertChildAt(aIdx, aAccessible); + if (inserted && mNativeObject) + [mNativeObject appendChild:aAccessible]; + + return inserted; +} + +bool +AccessibleWrap::RemoveChild(Accessible* aAccessible) +{ + bool removed = Accessible::RemoveChild(aAccessible); + + if (removed && mNativeObject) + [mNativeObject invalidateChildren]; + + return removed; +} + +//////////////////////////////////////////////////////////////////////////////// +// AccessibleWrap protected + +bool +AccessibleWrap::AncestorIsFlat() +{ + // We don't create a native object if we're child of a "flat" accessible; + // for example, on OS X buttons shouldn't have any children, because that + // makes the OS confused. + // + // To maintain a scripting environment where the XPCOM accessible hierarchy + // look the same on all platforms, we still let the C++ objects be created + // though. + + Accessible* parent = Parent(); + while (parent) { + if (nsAccUtils::MustPrune(parent)) + return true; + + parent = parent->Parent(); + } + // no parent was flat + return false; +} + +void +a11y::FireNativeEvent(mozAccessible* aNativeAcc, uint32_t aEventType) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + switch (aEventType) { + case nsIAccessibleEvent::EVENT_FOCUS: + [aNativeAcc didReceiveFocus]; + break; + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: + case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE: + [aNativeAcc valueDidChange]; + break; + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: + [aNativeAcc selectedTextDidChange]; + break; + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: + [aNativeAcc documentLoadComplete]; + break; + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +Class +a11y::GetTypeFromRole(roles::Role aRole) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + switch (aRole) { + case roles::COMBOBOX: + case roles::PUSHBUTTON: + case roles::SPLITBUTTON: + case roles::TOGGLE_BUTTON: + { + return [mozButtonAccessible class]; + } + + case roles::PAGETAB: + return [mozButtonAccessible class]; + + case roles::CHECKBUTTON: + return [mozCheckboxAccessible class]; + + case roles::HEADING: + return [mozHeadingAccessible class]; + + case roles::PAGETABLIST: + return [mozTabsAccessible class]; + + case roles::ENTRY: + case roles::STATICTEXT: + case roles::CAPTION: + case roles::ACCEL_LABEL: + case roles::PASSWORD_TEXT: + // normal textfield (static or editable) + return [mozTextAccessible class]; + + case roles::TEXT_LEAF: + return [mozTextLeafAccessible class]; + + case roles::LINK: + return [mozLinkAccessible class]; + + default: + return [mozAccessible class]; + } + + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} diff --git a/accessible/mac/ApplicationAccessibleWrap.h b/accessible/mac/ApplicationAccessibleWrap.h new file mode 100644 index 0000000000..9343c29ddc --- /dev/null +++ b/accessible/mac/ApplicationAccessibleWrap.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ApplicationAccessibleWrap_h__ +#define mozilla_a11y_ApplicationAccessibleWrap_h__ + +#include "ApplicationAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef ApplicationAccessible ApplicationAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/mac/DocAccessibleWrap.h b/accessible/mac/DocAccessibleWrap.h new file mode 100644 index 0000000000..3e80a0d33c --- /dev/null +++ b/accessible/mac/DocAccessibleWrap.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_DocAccessibleWrap_h__ +#define mozilla_a11y_DocAccessibleWrap_h__ + +#include "DocAccessible.h" + +namespace mozilla { +namespace a11y { + +class DocAccessibleWrap : public DocAccessible +{ +public: + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); + virtual ~DocAccessibleWrap(); + +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/DocAccessibleWrap.mm b/accessible/mac/DocAccessibleWrap.mm new file mode 100644 index 0000000000..8a513f485a --- /dev/null +++ b/accessible/mac/DocAccessibleWrap.mm @@ -0,0 +1,21 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DocAccessibleWrap.h" + +#import "mozAccessible.h" + +using namespace mozilla::a11y; + +DocAccessibleWrap:: + DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + DocAccessible(aDocument, aPresShell) +{ +} + +DocAccessibleWrap::~DocAccessibleWrap() +{ +} + diff --git a/accessible/mac/HTMLTableAccessibleWrap.h b/accessible/mac/HTMLTableAccessibleWrap.h new file mode 100644 index 0000000000..4f158e241d --- /dev/null +++ b/accessible/mac/HTMLTableAccessibleWrap.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_HTMLTableAccessibleWrap_h__ +#define mozilla_a11y_HTMLTableAccessibleWrap_h__ + +#include "HTMLTableAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class HTMLTableAccessible HTMLTableAccessibleWrap; +typedef class HTMLTableCellAccessible HTMLTableCellAccessibleWrap; +typedef class HTMLTableHeaderCellAccessible HTMLTableHeaderCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/mac/HyperTextAccessibleWrap.h b/accessible/mac/HyperTextAccessibleWrap.h new file mode 100644 index 0000000000..fb335ef0f7 --- /dev/null +++ b/accessible/mac/HyperTextAccessibleWrap.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_HyperTextAccessibleWrap_h__ +#define mozilla_a11y_HyperTextAccessibleWrap_h__ + +#include "HyperTextAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class HyperTextAccessible HyperTextAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/mac/ImageAccessibleWrap.h b/accessible/mac/ImageAccessibleWrap.h new file mode 100644 index 0000000000..069efb6511 --- /dev/null +++ b/accessible/mac/ImageAccessibleWrap.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_ImageAccessibleWrap_h__ +#define mozilla_a11y_ImageAccessibleWrap_h__ + +#include "ImageAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class ImageAccessible ImageAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif + diff --git a/accessible/mac/MacUtils.h b/accessible/mac/MacUtils.h new file mode 100644 index 0000000000..f88a27ee58 --- /dev/null +++ b/accessible/mac/MacUtils.h @@ -0,0 +1,26 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MacUtils_H_ +#define _MacUtils_H_ + +@class NSString; +class nsString; + +namespace mozilla { +namespace a11y { +namespace utils { + +/** + * Get a localized string from the string bundle. + * Return nil if not found. + */ +NSString* LocalizedString(const nsString& aString); + +} +} +} + +#endif diff --git a/accessible/mac/MacUtils.mm b/accessible/mac/MacUtils.mm new file mode 100644 index 0000000000..2ce03fe966 --- /dev/null +++ b/accessible/mac/MacUtils.mm @@ -0,0 +1,32 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "MacUtils.h" + +#include "Accessible.h" + +#include "nsCocoaUtils.h" + +namespace mozilla { +namespace a11y { +namespace utils { + +/** + * Get a localized string from the a11y string bundle. + * Return nil if not found. + */ +NSString* +LocalizedString(const nsString& aString) +{ + nsString text; + + Accessible::TranslateString(aString, text); + + return text.IsEmpty() ? nil : nsCocoaUtils::ToNSString(text); +} + +} +} +} diff --git a/accessible/mac/Platform.mm b/accessible/mac/Platform.mm new file mode 100644 index 0000000000..a104bf904c --- /dev/null +++ b/accessible/mac/Platform.mm @@ -0,0 +1,174 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import + +#include "Platform.h" +#include "ProxyAccessible.h" +#include "DocAccessibleParent.h" +#include "mozTableAccessible.h" + +#include "nsAppShell.h" + +namespace mozilla { +namespace a11y { + +// Mac a11y whitelisting +static bool sA11yShouldBeEnabled = false; + +bool +ShouldA11yBeEnabled() +{ + EPlatformDisabledState disabledState = PlatformDisabledState(); + return (disabledState == ePlatformIsForceEnabled) || ((disabledState == ePlatformIsEnabled) && sA11yShouldBeEnabled); +} + +void +PlatformInit() +{ +} + +void +PlatformShutdown() +{ +} + +void +ProxyCreated(ProxyAccessible* aProxy, uint32_t) +{ + // Pass in dummy state for now as retrieving proxy state requires IPC. + // Note that we can use ProxyAccessible::IsTable* functions here because they + // do not use IPC calls but that might change after bug 1210477. + Class type; + if (aProxy->IsTable()) + type = [mozTableAccessible class]; + else if (aProxy->IsTableRow()) + type = [mozTableRowAccessible class]; + else if (aProxy->IsTableCell()) + type = [mozTableCellAccessible class]; + else + type = GetTypeFromRole(aProxy->Role()); + + uintptr_t accWrap = reinterpret_cast(aProxy) | IS_PROXY; + mozAccessible* mozWrapper = [[type alloc] initWithAccessible:accWrap]; + aProxy->SetWrapper(reinterpret_cast(mozWrapper)); + + mozAccessible* nativeParent = nullptr; + if (aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevel()) { + // If proxy is top level, the parent we need to invalidate the children of + // will be a non-remote accessible. + Accessible* outerDoc = aProxy->OuterDocOfRemoteBrowser(); + if (outerDoc) { + nativeParent = GetNativeFromGeckoAccessible(outerDoc); + } + } else { + // Non-top level proxies need proxy parents' children invalidated. + ProxyAccessible* parent = aProxy->Parent(); + nativeParent = GetNativeFromProxy(parent); + NS_ASSERTION(parent, "a non-top-level proxy is missing a parent?"); + } + + if (nativeParent) { + [nativeParent invalidateChildren]; + } +} + +void +ProxyDestroyed(ProxyAccessible* aProxy) +{ + mozAccessible* nativeParent = nil; + if (aProxy->IsDoc() && aProxy->AsDoc()->IsTopLevel()) { + // Invalidate native parent in parent process's children on proxy destruction + Accessible* outerDoc = aProxy->OuterDocOfRemoteBrowser(); + if (outerDoc) { + nativeParent = GetNativeFromGeckoAccessible(outerDoc); + } + } else { + if (!aProxy->Document()->IsShutdown()) { + // Only do if the document has not been shut down, else parent will return + // garbage since we don't shut down children from top down. + ProxyAccessible* parent = aProxy->Parent(); + // Invalidate proxy parent's children. + if (parent) { + nativeParent = GetNativeFromProxy(parent); + } + } + } + + mozAccessible* wrapper = GetNativeFromProxy(aProxy); + [wrapper expire]; + [wrapper release]; + aProxy->SetWrapper(0); + + if (nativeParent) { + [nativeParent invalidateChildren]; + } +} + +void +ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType) +{ + // ignore everything but focus-changed, value-changed, caret and selection + // events for now. + if (aEventType != nsIAccessibleEvent::EVENT_FOCUS && + aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && + aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE && + aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && + aEventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) + return; + + mozAccessible* wrapper = GetNativeFromProxy(aProxy); + if (wrapper) + FireNativeEvent(wrapper, aEventType); +} + +void +ProxyStateChangeEvent(ProxyAccessible* aProxy, uint64_t, bool) +{ + // mac doesn't care about state change events +} + +void +ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset) +{ + mozAccessible* wrapper = GetNativeFromProxy(aTarget); + if (wrapper) + [wrapper selectedTextDidChange]; +} + +void +ProxyTextChangeEvent(ProxyAccessible*, const nsString&, int32_t, uint32_t, + bool, bool) +{ +} + +void +ProxyShowHideEvent(ProxyAccessible*, ProxyAccessible*, bool, bool) +{ +} + +void +ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t) +{ +} +} // namespace a11y +} // namespace mozilla + +@interface GeckoNSApplication(a11y) +-(void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute; +@end + +@implementation GeckoNSApplication(a11y) + +-(void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute +{ + if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) + mozilla::a11y::sA11yShouldBeEnabled = ([value intValue] == 1); + + return [super accessibilitySetValue:value forAttribute:attribute]; +} + +@end + diff --git a/accessible/mac/RootAccessibleWrap.h b/accessible/mac/RootAccessibleWrap.h new file mode 100644 index 0000000000..aa53e06ac0 --- /dev/null +++ b/accessible/mac/RootAccessibleWrap.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* For documentation of the accessibility architecture, + * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html + */ + +#ifndef mozilla_a11y_RootAccessibleWrap_h__ +#define mozilla_a11y_RootAccessibleWrap_h__ + +#include "RootAccessible.h" + +namespace mozilla { +namespace a11y { + +class RootAccessibleWrap : public RootAccessible +{ +public: + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell); + virtual ~RootAccessibleWrap(); + + Class GetNativeType (); + + // let's our native accessible get in touch with the + // native cocoa view that is our accessible parent. + void GetNativeWidget (void **aOutView); +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/RootAccessibleWrap.mm b/accessible/mac/RootAccessibleWrap.mm new file mode 100644 index 0000000000..037545cce2 --- /dev/null +++ b/accessible/mac/RootAccessibleWrap.mm @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RootAccessibleWrap.h" + +#include "mozDocAccessible.h" + +#include "nsCOMPtr.h" +#include "nsObjCExceptions.h" +#include "nsIFrame.h" +#include "nsView.h" +#include "nsIWidget.h" + +using namespace mozilla::a11y; + +RootAccessibleWrap:: + RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) : + RootAccessible(aDocument, aPresShell) +{ +} + +RootAccessibleWrap::~RootAccessibleWrap() +{ +} + +Class +RootAccessibleWrap::GetNativeType() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + return [mozRootAccessible class]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +void +RootAccessibleWrap::GetNativeWidget(void** aOutView) +{ + nsIFrame *frame = GetFrame(); + if (frame) { + nsView *view = frame->GetView(); + if (view) { + nsIWidget *widget = view->GetWidget(); + if (widget) { + *aOutView = (void**)widget->GetNativeData (NS_NATIVE_WIDGET); + NS_ASSERTION (*aOutView, + "Couldn't get the native NSView parent we need to connect the accessibility hierarchy!"); + } + } + } +} diff --git a/accessible/mac/TextLeafAccessibleWrap.h b/accessible/mac/TextLeafAccessibleWrap.h new file mode 100644 index 0000000000..d07b9defec --- /dev/null +++ b/accessible/mac/TextLeafAccessibleWrap.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_TextLeafAccessibleWrap_h__ +#define mozilla_a11y_TextLeafAccessibleWrap_h__ + +#include "TextLeafAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class TextLeafAccessible TextLeafAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/XULListboxAccessibleWrap.h b/accessible/mac/XULListboxAccessibleWrap.h new file mode 100644 index 0000000000..f7dc6cc547 --- /dev/null +++ b/accessible/mac/XULListboxAccessibleWrap.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULListboxAccessibleWrap_h__ +#define mozilla_a11y_XULListboxAccessibleWrap_h__ + +#include "XULListboxAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULListboxAccessible XULListboxAccessibleWrap; +typedef class XULListCellAccessible XULListCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/XULMenuAccessibleWrap.h b/accessible/mac/XULMenuAccessibleWrap.h new file mode 100644 index 0000000000..6efcf007eb --- /dev/null +++ b/accessible/mac/XULMenuAccessibleWrap.h @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULMenuAccessibleWrap_h__ +#define mozilla_a11y_XULMenuAccessibleWrap_h__ + +#include "XULMenuAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULMenuitemAccessible XULMenuitemAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/XULTreeGridAccessibleWrap.h b/accessible/mac/XULTreeGridAccessibleWrap.h new file mode 100644 index 0000000000..b3631e9adb --- /dev/null +++ b/accessible/mac/XULTreeGridAccessibleWrap.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_a11y_XULTreeGridAccessibleWrap_h__ +#define mozilla_a11y_XULTreeGridAccessibleWrap_h__ + +#include "XULTreeGridAccessible.h" + +namespace mozilla { +namespace a11y { + +typedef class XULTreeGridAccessible XULTreeGridAccessibleWrap; +typedef class XULTreeGridCellAccessible XULTreeGridCellAccessibleWrap; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/mac/moz.build b/accessible/mac/moz.build new file mode 100644 index 0000000000..8d2e7b391f --- /dev/null +++ b/accessible/mac/moz.build @@ -0,0 +1,44 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + 'mozAccessibleProtocol.h', +] + +EXPORTS.mozilla.a11y += [ + 'AccessibleWrap.h', + 'HyperTextAccessibleWrap.h', +] + +SOURCES += [ + 'AccessibleWrap.mm', + 'DocAccessibleWrap.mm', + 'MacUtils.mm', + 'mozAccessible.mm', + 'mozActionElements.mm', + 'mozDocAccessible.mm', + 'mozHTMLAccessible.mm', + 'mozTableAccessible.mm', + 'mozTextAccessible.mm', + 'Platform.mm', + 'RootAccessibleWrap.mm', +] + +LOCAL_INCLUDES += [ + '/accessible/base', + '/accessible/generic', + '/accessible/html', + '/accessible/ipc', + '/accessible/ipc/other', + '/accessible/xul', + '/layout/generic', + '/layout/xul', + '/widget', + '/widget/cocoa', +] + +FINAL_LIBRARY = 'xul' + +include('/ipc/chromium/chromium-config.mozbuild') diff --git a/accessible/mac/mozAccessible.h b/accessible/mac/mozAccessible.h new file mode 100644 index 0000000000..6d7db3fe98 --- /dev/null +++ b/accessible/mac/mozAccessible.h @@ -0,0 +1,181 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AccessibleWrap.h" +#include "ProxyAccessible.h" + +#import + +#import "mozAccessibleProtocol.h" + +@class mozRootAccessible; + +/** + * All mozAccessibles are either abstract objects (that correspond to XUL + * widgets, HTML frames, etc) or are attached to a certain view; for example + * a document view. When we hand an object off to an AT, we always want + * to give it the represented view, in the latter case. + */ + +namespace mozilla { +namespace a11y { + +inline id +GetObjectOrRepresentedView(id aObject) +{ + return [aObject hasRepresentedView] ? [aObject representedView] : aObject; +} + +inline mozAccessible* +GetNativeFromGeckoAccessible(Accessible* aAccessible) +{ + mozAccessible* native = nil; + aAccessible->GetNativeInterface((void**)&native); + return native; +} + +inline mozAccessible* +GetNativeFromProxy(const ProxyAccessible* aProxy) +{ + return reinterpret_cast(aProxy->GetWrapper()); +} + +} // a11y +} // mozilla + +// This is OR'd with the Accessible owner to indicate the wrap-ee is a proxy. +static const uintptr_t IS_PROXY = 1; + +@interface mozAccessible : NSObject +{ + /** + * Weak reference; it owns us. + */ + uintptr_t mGeckoAccessible; + + /** + * Strong ref to array of children + */ + NSMutableArray* mChildren; + + /** + * Weak reference to the parent + */ + mozAccessible* mParent; + + /** + * The role of our gecko accessible. + */ + mozilla::a11y::role mRole; +} + +// return the Accessible for this mozAccessible if it exists. +- (mozilla::a11y::AccessibleWrap*)getGeckoAccessible; + +// return the ProxyAccessible for this mozAccessible if it exists. +- (mozilla::a11y::ProxyAccessible*)getProxyAccessible; + +// inits with the gecko owner. +- (id)initWithAccessible:(uintptr_t)aGeckoObj; + +// our accessible parent (AXParent) +- (id )parent; + +// a lazy cache of our accessible children (AXChildren). updated +- (NSArray*)children; + +// returns the size of this accessible. +- (NSValue*)size; + +// returns the position, in cocoa coordinates. +- (NSValue*)position; + +// can be overridden to report another role name. +- (NSString*)role; + +// a subrole is a more specialized variant of the role. for example, +// the role might be "textfield", while the subrole is "password textfield". +- (NSString*)subrole; + +// Return the role description, as there are a few exceptions. +- (NSString*)roleDescription; + +// returns the native window we're inside. +- (NSWindow*)window; + +// the value of this element. +- (id)value; + +// name that is associated with this accessible (for buttons, etc) +- (NSString*)title; + +// the accessible description (help text) of this particular instance. +- (NSString*)help; + +- (BOOL)isEnabled; + +// information about focus. +- (BOOL)isFocused; +- (BOOL)canBeFocused; + +// returns NO if for some reason we were unable to focus the element. +- (BOOL)focus; + +// notifications sent out to listening accessible providers. +- (void)didReceiveFocus; +- (void)valueDidChange; +- (void)selectedTextDidChange; +- (void)documentLoadComplete; + +// internal method to retrieve a child at a given index. +- (id)childAt:(uint32_t)i; + +#pragma mark - + +// invalidates and removes all our children from our cached array. +- (void)invalidateChildren; + +/** + * Append a child if they are already cached. + */ +- (void)appendChild:(mozilla::a11y::Accessible*)aAccessible; + +// makes ourselves "expired". after this point, we might be around if someone +// has retained us (e.g., a third-party), but we really contain no information. +- (void)expire; +- (BOOL)isExpired; + +#ifdef DEBUG +- (void)printHierarchy; +- (void)printHierarchyWithLevel:(unsigned)numSpaces; + +- (void)sanityCheckChildren; +- (void)sanityCheckChildren:(NSArray*)theChildren; +#endif + +// ---- NSAccessibility methods ---- // + +// whether to skip this element when traversing the accessibility +// hierarchy. +- (BOOL)accessibilityIsIgnored; + +// called by third-parties to determine the deepest child element under the mouse +- (id)accessibilityHitTest:(NSPoint)point; + +// returns the deepest unignored focused accessible element +- (id)accessibilityFocusedUIElement; + +// a mozAccessible needs to at least provide links to its parent and +// children. +- (NSArray*)accessibilityAttributeNames; + +// value for the specified attribute +- (id)accessibilityAttributeValue:(NSString*)attribute; + +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute; +- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute; + +@end + diff --git a/accessible/mac/mozAccessible.mm b/accessible/mac/mozAccessible.mm new file mode 100644 index 0000000000..a02779ef25 --- /dev/null +++ b/accessible/mac/mozAccessible.mm @@ -0,0 +1,1197 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozAccessible.h" + +#import "MacUtils.h" +#import "mozView.h" + +#include "Accessible-inl.h" +#include "nsAccUtils.h" +#include "nsIAccessibleRelation.h" +#include "nsIAccessibleEditableText.h" +#include "nsIPersistentProperties2.h" +#include "Relation.h" +#include "Role.h" +#include "RootAccessible.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "mozilla/a11y/PDocAccessible.h" +#include "OuterDocAccessible.h" + +#include "mozilla/Services.h" +#include "nsRect.h" +#include "nsCocoaUtils.h" +#include "nsCoord.h" +#include "nsObjCExceptions.h" +#include "nsWhitespaceTokenizer.h" +#include + +using namespace mozilla; +using namespace mozilla::a11y; + +#define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand" +#define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex" +#define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator" +#define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator" +#define NSAccessibilityMathBaseAttribute @"AXMathBase" +#define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript" +#define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript" +#define NSAccessibilityMathUnderAttribute @"AXMathUnder" +#define NSAccessibilityMathOverAttribute @"AXMathOver" +#define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness" +// XXX WebKit also defines the following attributes. +// See bugs 1176970 and 1176983. +// - NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen" +// - NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose" +// - NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts" +// - NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts" + +#pragma mark - + +@implementation mozAccessible + +- (id)initWithAccessible:(uintptr_t)aGeckoAccessible +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ((self = [super init])) { + mGeckoAccessible = aGeckoAccessible; + if (aGeckoAccessible & IS_PROXY) + mRole = [self getProxyAccessible]->Role(); + else + mRole = [self getGeckoAccessible]->Role(); + } + + return self; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (void)dealloc +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [mChildren release]; + [super dealloc]; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (mozilla::a11y::AccessibleWrap*)getGeckoAccessible +{ + // Check if mGeckoAccessible points at a proxy + if (mGeckoAccessible & IS_PROXY) + return nil; + + return reinterpret_cast(mGeckoAccessible); +} + +- (mozilla::a11y::ProxyAccessible*)getProxyAccessible +{ + // Check if mGeckoAccessible points at a proxy + if (!(mGeckoAccessible & IS_PROXY)) + return nil; + + return reinterpret_cast(mGeckoAccessible & ~IS_PROXY); +} + +#pragma mark - + +- (BOOL)accessibilityIsIgnored +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + // unknown (either unimplemented, or irrelevant) elements are marked as ignored + // as well as expired elements. + + bool noRole = [[self role] isEqualToString:NSAccessibilityUnknownRole]; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + return (noRole && !(accWrap->InteractiveState() & states::FOCUSABLE)); + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return (noRole && !(proxy->State() & states::FOCUSABLE)); + + return true; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); +} + +- (NSArray*)additionalAccessibilityAttributeNames +{ + NSMutableArray* additional = [NSMutableArray array]; + switch (mRole) { + case roles::MATHML_ROOT: + [additional addObject:NSAccessibilityMathRootIndexAttribute]; + [additional addObject:NSAccessibilityMathRootRadicandAttribute]; + break; + case roles::MATHML_SQUARE_ROOT: + [additional addObject:NSAccessibilityMathRootRadicandAttribute]; + break; + case roles::MATHML_FRACTION: + [additional addObject:NSAccessibilityMathFractionNumeratorAttribute]; + [additional addObject:NSAccessibilityMathFractionDenominatorAttribute]; + [additional addObject:NSAccessibilityMathLineThicknessAttribute]; + break; + case roles::MATHML_SUB: + case roles::MATHML_SUP: + case roles::MATHML_SUB_SUP: + [additional addObject:NSAccessibilityMathBaseAttribute]; + [additional addObject:NSAccessibilityMathSubscriptAttribute]; + [additional addObject:NSAccessibilityMathSuperscriptAttribute]; + break; + case roles::MATHML_UNDER: + case roles::MATHML_OVER: + case roles::MATHML_UNDER_OVER: + [additional addObject:NSAccessibilityMathBaseAttribute]; + [additional addObject:NSAccessibilityMathUnderAttribute]; + [additional addObject:NSAccessibilityMathOverAttribute]; + break; + // XXX bug 1176983 + // roles::MATHML_MULTISCRIPTS should also have the following attributes: + // - NSAccessibilityMathPrescriptsAttribute + // - NSAccessibilityMathPostscriptsAttribute + // XXX bug 1176970 + // roles::MATHML_FENCED should also have the following attributes: + // - NSAccessibilityMathFencedOpenAttribute + // - NSAccessibilityMathFencedCloseAttribute + default: + break; + } + + return additional; +} + +- (NSArray*)accessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + // if we're expired, we don't support any attributes. + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) + return [NSArray array]; + + static NSArray* generalAttributes = nil; + + if (!generalAttributes) { + // standard attributes that are shared and supported by all generic elements. + generalAttributes = [[NSArray alloc] initWithObjects: NSAccessibilityChildrenAttribute, + NSAccessibilityParentAttribute, + NSAccessibilityRoleAttribute, + NSAccessibilityTitleAttribute, + NSAccessibilityValueAttribute, + NSAccessibilitySubroleAttribute, + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityPositionAttribute, + NSAccessibilityEnabledAttribute, + NSAccessibilitySizeAttribute, + NSAccessibilityWindowAttribute, + NSAccessibilityFocusedAttribute, + NSAccessibilityHelpAttribute, + NSAccessibilityTitleUIElementAttribute, + NSAccessibilityTopLevelUIElementAttribute, +#if DEBUG + @"AXMozDescription", +#endif + nil]; + } + + NSArray* objectAttributes = generalAttributes; + + NSArray* additionalAttributes = [self additionalAccessibilityAttributeNames]; + if ([additionalAttributes count]) + objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes]; + + return objectAttributes; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)childAt:(uint32_t)i +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + Accessible* child = accWrap->GetChildAt(i); + return child ? GetNativeFromGeckoAccessible(child) : nil; + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + ProxyAccessible* child = proxy->ChildAt(i); + return child ? GetNativeFromProxy(child) : nil; + } + + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) + return nil; + +#if DEBUG + if ([attribute isEqualToString:@"AXMozDescription"]) + return [NSString stringWithFormat:@"role = %u native = %@", mRole, [self class]]; +#endif + + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) + return [self children]; + if ([attribute isEqualToString:NSAccessibilityParentAttribute]) + return [self parent]; + +#ifdef DEBUG_hakan + NSLog (@"(%@ responding to attr %@)", self, attribute); +#endif + + if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) + return [self role]; + if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) + return [self position]; + if ([attribute isEqualToString:NSAccessibilitySubroleAttribute]) + return [self subrole]; + if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) + return [NSNumber numberWithBool:[self isEnabled]]; + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) + return [self value]; + if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) + return [self roleDescription]; + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) + return [NSNumber numberWithBool:[self isFocused]]; + if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) + return [self size]; + if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) + return [self window]; + if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) + return [self window]; + if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) + return [self title]; + if ([attribute isEqualToString:NSAccessibilityTitleUIElementAttribute]) { + if (accWrap) { + Relation rel = accWrap->RelationByType(RelationType::LABELLED_BY); + Accessible* tempAcc = rel.Next(); + return tempAcc ? GetNativeFromGeckoAccessible(tempAcc) : nil; + } + nsTArray rel = proxy->RelationByType(RelationType::LABELLED_BY); + ProxyAccessible* tempProxy = rel.SafeElementAt(0); + return tempProxy ? GetNativeFromProxy(tempProxy) : nil; + } + if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) + return [self help]; + + switch (mRole) { + case roles::MATHML_ROOT: + if ([attribute isEqualToString:NSAccessibilityMathRootRadicandAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathRootIndexAttribute]) + return [self childAt:1]; + break; + case roles::MATHML_SQUARE_ROOT: + if ([attribute isEqualToString:NSAccessibilityMathRootRadicandAttribute]) + return [self childAt:0]; + break; + case roles::MATHML_FRACTION: + if ([attribute isEqualToString:NSAccessibilityMathFractionNumeratorAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathFractionDenominatorAttribute]) + return [self childAt:1]; + if ([attribute isEqualToString:NSAccessibilityMathLineThicknessAttribute]) { + // WebKit sets line thickness to some logical value parsed in the + // renderer object of the element. It's not clear whether the + // exact value is relevant to assistive technologies. From a semantic + // point of view, the only important point is to distinguish between + // elements that have a fraction bar and those that do not. + // Per the MathML 3 spec, the latter happens iff the linethickness + // attribute is of the form [zero-float][optional-unit]. In that case we + // set line thickness to zero and in the other cases we set it to one. + nsAutoString thickness; + if (accWrap) { + nsCOMPtr attributes = accWrap->Attributes(); + nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness); + } else { + AutoTArray attrs; + proxy->Attributes(&attrs); + for (size_t i = 0 ; i < attrs.Length() ; i++) { + if (attrs.ElementAt(i).Name() == "thickness") { + thickness = attrs.ElementAt(i).Value(); + break; + } + } + } + double value = 1.0; + if (!thickness.IsEmpty()) + value = PR_strtod(NS_LossyConvertUTF16toASCII(thickness).get(), + nullptr); + return [NSNumber numberWithInteger:(value ? 1 : 0)]; + } + break; + case roles::MATHML_SUB: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathSubscriptAttribute]) + return [self childAt:1]; +#ifdef DEBUG + if ([attribute isEqualToString:NSAccessibilityMathSuperscriptAttribute]) + return nil; +#endif + break; + case roles::MATHML_SUP: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; +#ifdef DEBUG + if ([attribute isEqualToString:NSAccessibilityMathSubscriptAttribute]) + return nil; +#endif + if ([attribute isEqualToString:NSAccessibilityMathSuperscriptAttribute]) + return [self childAt:1]; + break; + case roles::MATHML_SUB_SUP: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathSubscriptAttribute]) + return [self childAt:1]; + if ([attribute isEqualToString:NSAccessibilityMathSuperscriptAttribute]) + return [self childAt:2]; + break; + case roles::MATHML_UNDER: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathUnderAttribute]) + return [self childAt:1]; +#ifdef DEBUG + if ([attribute isEqualToString:NSAccessibilityMathOverAttribute]) + return nil; +#endif + break; + case roles::MATHML_OVER: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; +#ifdef DEBUG + if ([attribute isEqualToString:NSAccessibilityMathUnderAttribute]) + return nil; +#endif + if ([attribute isEqualToString:NSAccessibilityMathOverAttribute]) + return [self childAt:1]; + break; + case roles::MATHML_UNDER_OVER: + if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute]) + return [self childAt:0]; + if ([attribute isEqualToString:NSAccessibilityMathUnderAttribute]) + return [self childAt:1]; + if ([attribute isEqualToString:NSAccessibilityMathOverAttribute]) + return [self childAt:2]; + break; + // XXX bug 1176983 + // roles::MATHML_MULTISCRIPTS should also have the following attributes: + // - NSAccessibilityMathPrescriptsAttribute + // - NSAccessibilityMathPostscriptsAttribute + // XXX bug 1176970 + // roles::MATHML_FENCED should also have the following attributes: + // - NSAccessibilityMathFencedOpenAttribute + // - NSAccessibilityMathFencedCloseAttribute + default: + break; + } + +#ifdef DEBUG + NSLog (@"!!! %@ can't respond to attribute %@", self, attribute); +#endif + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) + return [self canBeFocused]; + + return NO; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + +#ifdef DEBUG_hakan + NSLog (@"[%@] %@='%@'", self, attribute, value); +#endif + + // we only support focusing elements so far. + if ([attribute isEqualToString:NSAccessibilityFocusedAttribute] && [value boolValue]) + [self focus]; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (id)accessibilityHitTest:(NSPoint)point +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) + return nil; + + // Convert the given screen-global point in the cocoa coordinate system (with + // origin in the bottom-left corner of the screen) into point in the Gecko + // coordinate system (with origin in a top-left screen point). + NSScreen* mainView = [[NSScreen screens] objectAtIndex:0]; + NSPoint tmpPoint = NSMakePoint(point.x, + [mainView frame].size.height - point.y); + LayoutDeviceIntPoint geckoPoint = nsCocoaUtils:: + CocoaPointsToDevPixels(tmpPoint, nsCocoaUtils::GetBackingScaleFactor(mainView)); + + mozAccessible* nativeChild = nil; + if (accWrap) { + Accessible* child = accWrap->ChildAtPoint(geckoPoint.x, geckoPoint.y, + Accessible::eDeepestChild); + if (child) + nativeChild = GetNativeFromGeckoAccessible(child); + } else if (proxy) { + ProxyAccessible* child = proxy->ChildAtPoint(geckoPoint.x, geckoPoint.y, + Accessible::eDeepestChild); + if (child) + nativeChild = GetNativeFromProxy(child); + } + + if (nativeChild) + return nativeChild; + + // if we didn't find anything, return ourself or child view. + return GetObjectOrRepresentedView(self); +} + +- (NSArray*)accessibilityActionNames +{ + return nil; +} + +- (NSString*)accessibilityActionDescription:(NSString*)action +{ + // by default we return whatever the MacOS API know about. + // if you have custom actions, override. + return NSAccessibilityActionDescription(action); +} + +- (void)accessibilityPerformAction:(NSString*)action +{ +} + +- (id)accessibilityFocusedUIElement +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) + return nil; + + mozAccessible* focusedChild = nil; + if (accWrap) { + Accessible* focusedGeckoChild = accWrap->FocusedChild(); + if (focusedGeckoChild) + focusedChild = GetNativeFromGeckoAccessible(focusedGeckoChild); + } else if (proxy) { + ProxyAccessible* focusedGeckoChild = proxy->FocusedChild(); + if (focusedGeckoChild) + focusedChild = GetNativeFromProxy(focusedGeckoChild); + } + + if (focusedChild) + return GetObjectOrRepresentedView(focusedChild); + + // return ourself if we can't get a native focused child. + return GetObjectOrRepresentedView(self); +} + +#pragma mark - + +- (id )parent +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + id nativeParent = nil; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + Accessible* accessibleParent = accWrap->Parent(); + if (accessibleParent) + nativeParent = GetNativeFromGeckoAccessible(accessibleParent); + if (nativeParent) + return GetObjectOrRepresentedView(nativeParent); + + // Return native of root accessible if we have no direct parent + nativeParent = GetNativeFromGeckoAccessible(accWrap->RootAccessible()); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if (ProxyAccessible* proxyParent = proxy->Parent()) { + nativeParent = GetNativeFromProxy(proxyParent); + } + + if (nativeParent) + return GetObjectOrRepresentedView(nativeParent); + + Accessible* outerDoc = proxy->OuterDocOfRemoteBrowser(); + nativeParent = outerDoc ? + GetNativeFromGeckoAccessible(outerDoc) : nil; + } else { + return nil; + } + + NSAssert1 (nativeParent, @"!!! we can't find a parent for %@", self); + + return GetObjectOrRepresentedView(nativeParent); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)hasRepresentedView +{ + return NO; +} + +- (id)representedView +{ + return nil; +} + +- (BOOL)isRoot +{ + return NO; +} + +// gets our native children lazily. +// returns nil when there are no children. +- (NSArray*)children +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (mChildren) + return mChildren; + + // get the array of children. + mChildren = [[NSMutableArray alloc] init]; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + if (accWrap) { + uint32_t childCount = accWrap->ChildCount(); + for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { + mozAccessible* nativeChild = GetNativeFromGeckoAccessible(accWrap->GetChildAt(childIdx)); + if (nativeChild) + [mChildren addObject:nativeChild]; + } + + // children from child if this is an outerdoc + OuterDocAccessible* docOwner = accWrap->AsOuterDoc(); + if (docOwner) { + if (ProxyAccessible* proxyDoc = docOwner->RemoteChildDoc()) { + mozAccessible* nativeRemoteChild = GetNativeFromProxy(proxyDoc); + [mChildren insertObject:nativeRemoteChild atIndex:0]; + NSAssert1 (nativeRemoteChild, @"%@ found a child remote doc missing a native\n", self); + } + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + uint32_t childCount = proxy->ChildrenCount(); + for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { + mozAccessible* nativeChild = GetNativeFromProxy(proxy->ChildAt(childIdx)); + if (nativeChild) + [mChildren addObject:nativeChild]; + } + + } + + return mChildren; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSValue*)position +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + nsIntRect rect; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + rect = accWrap->Bounds(); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + rect = proxy->Bounds(); + else + return nil; + + NSScreen* mainView = [[NSScreen screens] objectAtIndex:0]; + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView); + NSPoint p = NSMakePoint(static_cast(rect.x) / scaleFactor, + [mainView frame].size.height - static_cast(rect.y + rect.height) / scaleFactor); + + return [NSValue valueWithPoint:p]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSValue*)size +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + nsIntRect rect; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + rect = accWrap->Bounds(); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + rect = proxy->Bounds(); + else + return nil; + + CGFloat scaleFactor = + nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]); + return [NSValue valueWithSize:NSMakeSize(static_cast(rect.width) / scaleFactor, + static_cast(rect.height) / scaleFactor)]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSString*)role +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + if (accWrap) { + #ifdef DEBUG_A11Y + NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), + "Does not support Text when it should"); + #endif + } else if (![self getProxyAccessible]) { + return nil; + } + +#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \ + case roles::geckoRole: \ + return macRole; + + switch (mRole) { +#include "RoleMap.h" + default: + NS_NOTREACHED("Unknown role."); + return NSAccessibilityUnknownRole; + } + +#undef ROLE +} + +- (NSString*)subrole +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + + // Deal with landmarks first + nsIAtom* landmark = nullptr; + if (accWrap) + landmark = accWrap->LandmarkRole(); + else if (proxy) + landmark = proxy->LandmarkRole(); + + if (landmark) { + if (landmark == nsGkAtoms::application) + return @"AXLandmarkApplication"; + if (landmark == nsGkAtoms::banner) + return @"AXLandmarkBanner"; + if (landmark == nsGkAtoms::complementary) + return @"AXLandmarkComplementary"; + if (landmark == nsGkAtoms::contentinfo) + return @"AXLandmarkContentInfo"; + if (landmark == nsGkAtoms::form) + return @"AXLandmarkForm"; + if (landmark == nsGkAtoms::main) + return @"AXLandmarkMain"; + if (landmark == nsGkAtoms::navigation) + return @"AXLandmarkNavigation"; + if (landmark == nsGkAtoms::search) + return @"AXLandmarkSearch"; + if (landmark == nsGkAtoms::searchbox) + return @"AXSearchField"; + } + + // Now, deal with widget roles + nsIAtom* roleAtom = nullptr; + if (accWrap && accWrap->HasARIARole()) { + const nsRoleMapEntry* roleMap = accWrap->ARIARoleMap(); + roleAtom = *roleMap->roleAtom; + } + if (proxy) + roleAtom = proxy->ARIARoleAtom(); + + if (roleAtom) { + if (roleAtom == nsGkAtoms::alert) + return @"AXApplicationAlert"; + if (roleAtom == nsGkAtoms::alertdialog) + return @"AXApplicationAlertDialog"; + if (roleAtom == nsGkAtoms::article) + return @"AXDocumentArticle"; + if (roleAtom == nsGkAtoms::dialog) + return @"AXApplicationDialog"; + if (roleAtom == nsGkAtoms::document) + return @"AXDocument"; + if (roleAtom == nsGkAtoms::log_) + return @"AXApplicationLog"; + if (roleAtom == nsGkAtoms::math) + return @"AXDocumentMath"; + if (roleAtom == nsGkAtoms::note_) + return @"AXDocumentNote"; + if (roleAtom == nsGkAtoms::region) + return @"AXDocumentRegion"; + if (roleAtom == nsGkAtoms::status) + return @"AXApplicationStatus"; + if (roleAtom == nsGkAtoms::tabpanel) + return @"AXTabPanel"; + if (roleAtom == nsGkAtoms::timer) + return @"AXApplicationTimer"; + if (roleAtom == nsGkAtoms::tooltip) + return @"AXUserInterfaceTooltip"; + } + + switch (mRole) { + case roles::LIST: + return @"AXContentList"; // 10.6+ NSAccessibilityContentListSubrole; + + case roles::ENTRY: + if ((accWrap && accWrap->IsSearchbox()) || + (proxy && proxy->IsSearchbox())) + return @"AXSearchField"; + break; + + case roles::DEFINITION_LIST: + return @"AXDefinitionList"; // 10.6+ NSAccessibilityDefinitionListSubrole; + + case roles::TERM: + return @"AXTerm"; + + case roles::DEFINITION: + return @"AXDefinition"; + + case roles::MATHML_MATH: + return @"AXDocumentMath"; + + case roles::MATHML_FRACTION: + return @"AXMathFraction"; + + case roles::MATHML_FENCED: + // XXX bug 1176970 + // This should be AXMathFence, but doing so without implementing the + // whole fence interface seems to make VoiceOver crash, so we present it + // as a row for now. + return @"AXMathRow"; + + case roles::MATHML_SUB: + case roles::MATHML_SUP: + case roles::MATHML_SUB_SUP: + return @"AXMathSubscriptSuperscript"; + + case roles::MATHML_ROW: + case roles::MATHML_STYLE: + case roles::MATHML_ERROR: + return @"AXMathRow"; + + case roles::MATHML_UNDER: + case roles::MATHML_OVER: + case roles::MATHML_UNDER_OVER: + return @"AXMathUnderOver"; + + case roles::MATHML_SQUARE_ROOT: + return @"AXMathSquareRoot"; + + case roles::MATHML_ROOT: + return @"AXMathRoot"; + + case roles::MATHML_TEXT: + return @"AXMathText"; + + case roles::MATHML_NUMBER: + return @"AXMathNumber"; + + case roles::MATHML_IDENTIFIER: + return @"AXMathIdentifier"; + + case roles::MATHML_TABLE: + return @"AXMathTable"; + + case roles::MATHML_TABLE_ROW: + return @"AXMathTableRow"; + + case roles::MATHML_CELL: + return @"AXMathTableCell"; + + // XXX: NSAccessibility also uses subroles AXMathSeparatorOperator and + // AXMathFenceOperator. We should use the NS_MATHML_OPERATOR_FENCE and + // NS_MATHML_OPERATOR_SEPARATOR bits of nsOperatorFlags, but currently they + // are only available from the MathML layout code. Hence we just fallback + // to subrole AXMathOperator for now. + // XXX bug 1175747 WebKit also creates anonymous operators for + // which have subroles AXMathSeparatorOperator and AXMathFenceOperator. + case roles::MATHML_OPERATOR: + return @"AXMathOperator"; + + case roles::MATHML_MULTISCRIPTS: + return @"AXMathMultiscript"; + + case roles::SWITCH: + return @"AXSwitch"; + + case roles::ALERT: + return @"AXApplicationAlert"; + + case roles::SEPARATOR: + return @"AXContentSeparator"; + + case roles::PROPERTYPAGE: + return @"AXTabPanel"; + + case roles::DETAILS: + return @"AXDetails"; + + case roles::SUMMARY: + return @"AXSummary"; + + default: + break; + } + + return nil; +} + +struct RoleDescrMap +{ + NSString* role; + const nsString description; +}; + +static const RoleDescrMap sRoleDescrMap[] = { + { @"AXApplicationAlert", NS_LITERAL_STRING("alert") }, + { @"AXApplicationAlertDialog", NS_LITERAL_STRING("alertDialog") }, + { @"AXApplicationLog", NS_LITERAL_STRING("log") }, + { @"AXApplicationStatus", NS_LITERAL_STRING("status") }, + { @"AXApplicationTimer", NS_LITERAL_STRING("timer") }, + { @"AXContentSeparator", NS_LITERAL_STRING("separator") }, + { @"AXDefinition", NS_LITERAL_STRING("definition") }, + { @"AXDocument", NS_LITERAL_STRING("document") }, + { @"AXDocumentArticle", NS_LITERAL_STRING("article") }, + { @"AXDocumentMath", NS_LITERAL_STRING("math") }, + { @"AXDocumentNote", NS_LITERAL_STRING("note") }, + { @"AXDocumentRegion", NS_LITERAL_STRING("region") }, + { @"AXLandmarkApplication", NS_LITERAL_STRING("application") }, + { @"AXLandmarkBanner", NS_LITERAL_STRING("banner") }, + { @"AXLandmarkComplementary", NS_LITERAL_STRING("complementary") }, + { @"AXLandmarkContentInfo", NS_LITERAL_STRING("content") }, + { @"AXLandmarkMain", NS_LITERAL_STRING("main") }, + { @"AXLandmarkNavigation", NS_LITERAL_STRING("navigation") }, + { @"AXLandmarkSearch", NS_LITERAL_STRING("search") }, + { @"AXSearchField", NS_LITERAL_STRING("searchTextField") }, + { @"AXTabPanel", NS_LITERAL_STRING("tabPanel") }, + { @"AXTerm", NS_LITERAL_STRING("term") }, + { @"AXUserInterfaceTooltip", NS_LITERAL_STRING("tooltip") } +}; + +struct RoleDescrComparator +{ + const NSString* mRole; + explicit RoleDescrComparator(const NSString* aRole) : mRole(aRole) {} + int operator()(const RoleDescrMap& aEntry) const { + return [mRole compare:aEntry.role]; + } +}; + +- (NSString*)roleDescription +{ + if (mRole == roles::DOCUMENT) + return utils::LocalizedString(NS_LITERAL_STRING("htmlContent")); + + NSString* subrole = [self subrole]; + + if (subrole) { + size_t idx = 0; + if (BinarySearchIf(sRoleDescrMap, 0, ArrayLength(sRoleDescrMap), + RoleDescrComparator(subrole), &idx)) { + return utils::LocalizedString(sRoleDescrMap[idx].description); + } + } + + return NSAccessibilityRoleDescription([self role], subrole); +} + +- (NSString*)title +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + nsAutoString title; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + accWrap->Name(title); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + proxy->Name(title); + + return nsCocoaUtils::ToNSString(title); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)value +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + nsAutoString value; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + accWrap->Value(value); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + proxy->Value(value); + + return nsCocoaUtils::ToNSString(value); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (void)valueDidChange +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + +#ifdef DEBUG_hakan + NSLog(@"%@'s value changed!", self); +#endif + // sending out a notification is expensive, so we don't do it other than for really important objects, + // like mozTextAccessible. + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)selectedTextDidChange +{ + // Do nothing. mozTextAccessible will. +} + +- (void)documentLoadComplete +{ + id realSelf = GetObjectOrRepresentedView(self); + NSAccessibilityPostNotification(realSelf, NSAccessibilityFocusedUIElementChangedNotification); + NSAccessibilityPostNotification(realSelf, @"AXLoadComplete"); + NSAccessibilityPostNotification(realSelf, @"AXLayoutComplete"); +} + +- (NSString*)help +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + // What needs to go here is actually the accDescription of an item. + // The MSAA acc_help method has nothing to do with this one. + nsAutoString helpText; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + accWrap->Description(helpText); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + proxy->Description(helpText); + + return nsCocoaUtils::ToNSString(helpText); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +// objc-style description (from NSObject); not to be confused with the accessible description above. +- (NSString*)description +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + return [NSString stringWithFormat:@"(%p) %@", self, [self role]]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)isFocused +{ + return FocusMgr()->IsFocused([self getGeckoAccessible]); +} + +- (BOOL)canBeFocused +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + return accWrap->InteractiveState() & states::FOCUSABLE; + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return proxy->State() & states::FOCUSABLE; + + return false; +} + +- (BOOL)focus +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + accWrap->TakeFocus(); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + proxy->TakeFocus(); + else + return NO; + + return YES; +} + +- (BOOL)isEnabled +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + return ((accWrap->InteractiveState() & states::UNAVAILABLE) == 0); + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return ((proxy->State() & states::UNAVAILABLE) == 0); + + return false; +} + +// The root accessible calls this when the focused node was +// changed to us. +- (void)didReceiveFocus +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + +#ifdef DEBUG_hakan + NSLog (@"%@ received focus!", self); +#endif + NSAccessibilityPostNotification(GetObjectOrRepresentedView(self), + NSAccessibilityFocusedUIElementChangedNotification); + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (NSWindow*)window +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + // Get a pointer to the native window (NSWindow) we reside in. + NSWindow *nativeWindow = nil; + DocAccessible* docAcc = nullptr; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + docAcc = accWrap->Document(); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + Accessible* outerDoc = proxy->OuterDocOfRemoteBrowser(); + if (outerDoc) + docAcc = outerDoc->Document(); + } + + if (docAcc) + nativeWindow = static_cast(docAcc->GetNativeWindow()); + + NSAssert1(nativeWindow, @"Could not get native window for %@", self); + return nativeWindow; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (void)invalidateChildren +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + // make room for new children + [mChildren release]; + mChildren = nil; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)appendChild:(Accessible*)aAccessible +{ + // if mChildren is nil, then we don't even need to bother + if (!mChildren) + return; + + mozAccessible *curNative = GetNativeFromGeckoAccessible(aAccessible); + if (curNative) + [mChildren addObject:curNative]; +} + +- (void)expire +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [self invalidateChildren]; + + mGeckoAccessible = 0; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (BOOL)isExpired +{ + return ![self getGeckoAccessible] && ![self getProxyAccessible]; +} + +#pragma mark - +#pragma mark Debug methods +#pragma mark - + +#ifdef DEBUG + +// will check that our children actually reference us as their +// parent. +- (void)sanityCheckChildren:(NSArray *)children +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + NSEnumerator *iter = [children objectEnumerator]; + mozAccessible *curObj = nil; + + NSLog(@"sanity checking %@", self); + + while ((curObj = [iter nextObject])) { + id realSelf = GetObjectOrRepresentedView(self); + NSLog(@"checking %@", realSelf); + NSAssert2([curObj parent] == realSelf, + @"!!! %@ not returning %@ as AXParent, even though it is a AXChild of it!", curObj, realSelf); + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)sanityCheckChildren +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [self sanityCheckChildren:[self children]]; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)printHierarchy +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [self printHierarchyWithLevel:0]; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)printHierarchyWithLevel:(unsigned)level +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + NSAssert(![self isExpired], @"!!! trying to print hierarchy of expired object!"); + + // print this node + NSMutableString *indent = [NSMutableString stringWithCapacity:level]; + unsigned i=0; + for (;i + +#import "mozView.h" + +/* This protocol's primary use is so widget/cocoa can talk back to us + properly. + + ChildView owns the topmost mozRootAccessible, and needs to take care of setting up + that parent/child relationship. + + This protocol is thus used to make sure it knows it's talking to us, and not + just some random |id|. +*/ + +@protocol mozAccessible + +// returns whether this accessible is the root accessible. there is one +// root accessible per window. +- (BOOL)isRoot; + +// some mozAccessibles implement accessibility support in place of another object. for example, +// ChildView gets its support from us. +// +// instead of returning a mozAccessible to the OS when it wants an object, we need to pass the view we represent, so the +// OS doesn't get confused and think we return some random object. +- (BOOL)hasRepresentedView; +- (id)representedView; + +#ifdef DEBUG +// debug utility that will print the native accessibility tree, starting +// at this node. +- (void)printHierarchy; +#endif + +/*** general ***/ + +// returns the accessible at the specified point. +- (id)accessibilityHitTest:(NSPoint)point; + +// whether this element is flagged as ignored. +- (BOOL)accessibilityIsIgnored; + +// currently focused UI element (possibly a child accessible) +- (id)accessibilityFocusedUIElement; + +/*** attributes ***/ + +// all supported attributes +- (NSArray*)accessibilityAttributeNames; + +// value for given attribute. +- (id)accessibilityAttributeValue:(NSString*)attribute; + +// whether a particular attribute can be modified +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute; + +/*** actions ***/ + +- (NSArray*)accessibilityActionNames; +- (NSString*)accessibilityActionDescription:(NSString*)action; +- (void)accessibilityPerformAction:(NSString*)action; + +@end + diff --git a/accessible/mac/mozActionElements.h b/accessible/mac/mozActionElements.h new file mode 100644 index 0000000000..a325921eb8 --- /dev/null +++ b/accessible/mac/mozActionElements.h @@ -0,0 +1,37 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#import "mozAccessible.h" + +/* Simple subclasses for things like checkboxes, buttons, etc. */ + +@interface mozButtonAccessible : mozAccessible + { + } +- (BOOL)hasPopup; +- (void)click; +- (BOOL)isTab; +@end + +@interface mozCheckboxAccessible : mozButtonAccessible +// returns one of the constants defined in CheckboxValue +- (int)isChecked; +@end + +/* Class for tabs - not individual tabs */ +@interface mozTabsAccessible : mozAccessible +{ + NSMutableArray* mTabs; +} +-(id)tabs; +@end + +/** + * Accessible for a PANE + */ +@interface mozPaneAccessible : mozAccessible + +@end diff --git a/accessible/mac/mozActionElements.mm b/accessible/mac/mozActionElements.mm new file mode 100644 index 0000000000..5decd6cccc --- /dev/null +++ b/accessible/mac/mozActionElements.mm @@ -0,0 +1,340 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozActionElements.h" + +#import "MacUtils.h" +#include "Accessible-inl.h" +#include "DocAccessible.h" +#include "XULTabAccessible.h" + +#include "nsDeckFrame.h" +#include "nsObjCExceptions.h" + +using namespace mozilla::a11y; + +enum CheckboxValue { + // these constants correspond to the values in the OS + kUnchecked = 0, + kChecked = 1, + kMixed = 2 +}; + +@implementation mozButtonAccessible + +- (NSArray*)accessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + static NSArray *attributes = nil; + if (!attributes) { + attributes = [[NSArray alloc] initWithObjects:NSAccessibilityParentAttribute, // required + NSAccessibilityRoleAttribute, // required + NSAccessibilityRoleDescriptionAttribute, + NSAccessibilityPositionAttribute, // required + NSAccessibilitySizeAttribute, // required + NSAccessibilityWindowAttribute, // required + NSAccessibilityPositionAttribute, // required + NSAccessibilityTopLevelUIElementAttribute, // required + NSAccessibilityHelpAttribute, + NSAccessibilityEnabledAttribute, // required + NSAccessibilityFocusedAttribute, // required + NSAccessibilityTitleAttribute, // required + NSAccessibilityChildrenAttribute, + NSAccessibilityDescriptionAttribute, +#if DEBUG + @"AXMozDescription", +#endif + nil]; + } + return attributes; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + if ([self hasPopup]) + return [self children]; + return nil; + } + + if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { + if ([self isTab]) + return utils::LocalizedString(NS_LITERAL_STRING("tab")); + + return NSAccessibilityRoleDescription([self role], nil); + } + + return [super accessibilityAttributeValue:attribute]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)accessibilityIsIgnored +{ + return ![self getGeckoAccessible] && ![self getProxyAccessible]; +} + +- (NSArray*)accessibilityActionNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([self isEnabled]) { + if ([self hasPopup]) + return [NSArray arrayWithObjects:NSAccessibilityPressAction, + NSAccessibilityShowMenuAction, + nil]; + return [NSArray arrayWithObject:NSAccessibilityPressAction]; + } + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSString*)accessibilityActionDescription:(NSString*)action +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([action isEqualToString:NSAccessibilityPressAction]) { + if ([self isTab]) + return utils::LocalizedString(NS_LITERAL_STRING("switch")); + + return @"press button"; // XXX: localize this later? + } + + if ([self hasPopup]) { + if ([action isEqualToString:NSAccessibilityShowMenuAction]) + return @"show menu"; + } + + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (void)accessibilityPerformAction:(NSString*)action +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + if ([self isEnabled] && [action isEqualToString:NSAccessibilityPressAction]) { + // TODO: this should bring up the menu, but currently doesn't. + // once msaa and atk have merged better, they will implement + // the action needed to show the menu. + [self click]; + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)click +{ + // both buttons and checkboxes have only one action. we should really stop using arbitrary + // arrays with actions, and define constants for these actions. + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + accWrap->DoAction(0); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + proxy->DoAction(0); +} + +- (BOOL)isTab +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + return accWrap->Role() == roles::PAGETAB; + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return proxy->Role() == roles::PAGETAB; + + return false; +} + +- (BOOL)hasPopup +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + return accWrap->NativeState() & states::HASPOPUP; + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return proxy->NativeState() & states::HASPOPUP; + + return false; +} + +@end + +@implementation mozCheckboxAccessible + +- (NSString*)accessibilityActionDescription:(NSString*)action +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([action isEqualToString:NSAccessibilityPressAction]) { + if ([self isChecked] != kUnchecked) + return @"uncheck checkbox"; // XXX: localize this later? + + return @"check checkbox"; // XXX: localize this later? + } + + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (int)isChecked +{ + uint64_t state = 0; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) + state = accWrap->NativeState(); + else if (ProxyAccessible* proxy = [self getProxyAccessible]) + state = proxy->NativeState(); + + // check if we're checked or in a mixed state + if (state & states::CHECKED) { + return (state & states::MIXED) ? kMixed : kChecked; + } + + return kUnchecked; +} + +- (id)value +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + return [NSNumber numberWithInt:[self isChecked]]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +@end + +@implementation mozTabsAccessible + +- (void)dealloc +{ + [mTabs release]; + + [super dealloc]; +} + +- (NSArray*)accessibilityAttributeNames +{ + // standard attributes that are shared and supported by root accessible (AXMain) elements. + static NSMutableArray* attributes = nil; + + if (!attributes) { + attributes = [[super accessibilityAttributeNames] mutableCopy]; + [attributes addObject:NSAccessibilityContentsAttribute]; + [attributes addObject:NSAccessibilityTabsAttribute]; + } + + return attributes; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute +{ + if ([attribute isEqualToString:NSAccessibilityContentsAttribute]) + return [super children]; + if ([attribute isEqualToString:NSAccessibilityTabsAttribute]) + return [self tabs]; + + return [super accessibilityAttributeValue:attribute]; +} + +/** + * Returns the selected tab (the mozAccessible) + */ +- (id)value +{ + mozAccessible* nativeAcc = nil; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + if (Accessible* accTab = accWrap->GetSelectedItem(0)) { + accTab->GetNativeInterface((void**)&nativeAcc); + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if (ProxyAccessible* proxyTab = proxy->GetSelectedItem(0)) { + nativeAcc = GetNativeFromProxy(proxyTab); + } + } + + return nativeAcc; +} + +/** + * Return the mozAccessibles that are the tabs. + */ +- (id)tabs +{ + if (mTabs) + return mTabs; + + NSArray* children = [self children]; + NSEnumerator* enumerator = [children objectEnumerator]; + mTabs = [[NSMutableArray alloc] init]; + + id obj; + while ((obj = [enumerator nextObject])) + if ([obj isTab]) + [mTabs addObject:obj]; + + return mTabs; +} + +- (void)invalidateChildren +{ + [super invalidateChildren]; + + [mTabs release]; + mTabs = nil; +} + +@end + +@implementation mozPaneAccessible + +- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) + return 0; + + // By default this calls -[[mozAccessible children] count]. + // Since we don't cache mChildren. This is faster. + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + if (accWrap) + return accWrap->ChildCount() ? 1 : 0; + + return proxy->ChildrenCount() ? 1 : 0; + } + + return [super accessibilityArrayAttributeCount:attribute]; +} + +- (NSArray*)children +{ + if (![self getGeckoAccessible]) + return nil; + + nsDeckFrame* deckFrame = do_QueryFrame([self getGeckoAccessible]->GetFrame()); + nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr; + + Accessible* selectedAcc = nullptr; + if (selectedFrame) { + nsINode* node = selectedFrame->GetContent(); + selectedAcc = [self getGeckoAccessible]->Document()->GetAccessible(node); + } + + if (selectedAcc) { + mozAccessible *curNative = GetNativeFromGeckoAccessible(selectedAcc); + if (curNative) + return [NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil]; + } + + return nil; +} + +@end diff --git a/accessible/mac/mozDocAccessible.h b/accessible/mac/mozDocAccessible.h new file mode 100644 index 0000000000..c381773110 --- /dev/null +++ b/accessible/mac/mozDocAccessible.h @@ -0,0 +1,31 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#import "mozAccessible.h" + +// our protocol that we implement (so cocoa widgets can talk to us) +#import "mozAccessibleProtocol.h" + +/* + The root accessible. There is one per window. + Created by the RootAccessibleWrap. +*/ +@interface mozRootAccessible : mozAccessible +{ + // the mozView that we're representing. + // all outside communication goes through the mozView. + // in reality, it's just piping all calls to us, and we're + // doing its dirty work! + // + // whenever someone asks who we are (e.g., a child asking + // for its parent, or our parent asking for its child), we'll + // respond the mozView. it is absolutely necessary for third- + // party tools that we do this! + // + // /hwaara + id mParallelView; // weak ref +} +@end diff --git a/accessible/mac/mozDocAccessible.mm b/accessible/mac/mozDocAccessible.mm new file mode 100644 index 0000000000..4bae81f01c --- /dev/null +++ b/accessible/mac/mozDocAccessible.mm @@ -0,0 +1,111 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RootAccessibleWrap.h" + +#import "mozDocAccessible.h" + +#import "mozView.h" + +// This must be included last: +#include "nsObjCExceptions.h" + +using namespace mozilla::a11y; + +static id +getNativeViewFromRootAccessible(Accessible* aAccessible) +{ + RootAccessibleWrap* root = + static_cast(aAccessible->AsRoot()); + id nativeView = nil; + root->GetNativeWidget ((void**)&nativeView); + return nativeView; +} + +#pragma mark - + +@implementation mozRootAccessible + +- (NSArray*)accessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + // if we're expired, we don't support any attributes. + if (![self getGeckoAccessible]) + return [NSArray array]; + + // standard attributes that are shared and supported by root accessible (AXMain) elements. + static NSMutableArray* attributes = nil; + + if (!attributes) { + attributes = [[super accessibilityAttributeNames] mutableCopy]; + [attributes addObject:NSAccessibilityMainAttribute]; + [attributes addObject:NSAccessibilityMinimizedAttribute]; + } + + return attributes; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([attribute isEqualToString:NSAccessibilityMainAttribute]) + return [NSNumber numberWithBool:[[self window] isMainWindow]]; + if ([attribute isEqualToString:NSAccessibilityMinimizedAttribute]) + return [NSNumber numberWithBool:[[self window] isMiniaturized]]; + + return [super accessibilityAttributeValue:attribute]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + + +// return the AXParent that our parallell NSView tells us about. +- (id)parent +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (!mParallelView) + mParallelView = (id)[self representedView]; + + if (mParallelView) + return [mParallelView accessibilityAttributeValue:NSAccessibilityParentAttribute]; + + NSAssert(mParallelView, @"we're a root accessible w/o native view?"); + return [super parent]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)hasRepresentedView +{ + return YES; +} + +// this will return our parallell NSView. see mozDocAccessible.h +- (id)representedView +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (mParallelView) + return (id)mParallelView; + + mParallelView = getNativeViewFromRootAccessible ([self getGeckoAccessible]); + + NSAssert(mParallelView, @"can't return root accessible's native parallel view."); + return mParallelView; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (BOOL)isRoot +{ + return YES; +} + +@end diff --git a/accessible/mac/mozHTMLAccessible.h b/accessible/mac/mozHTMLAccessible.h new file mode 100644 index 0000000000..c70a3c2a25 --- /dev/null +++ b/accessible/mac/mozHTMLAccessible.h @@ -0,0 +1,16 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozAccessible.h" + +@interface mozHeadingAccessible : mozAccessible + +@end + +@interface mozLinkAccessible : mozAccessible + +@end diff --git a/accessible/mac/mozHTMLAccessible.mm b/accessible/mac/mozHTMLAccessible.mm new file mode 100644 index 0000000000..2079a4aa6b --- /dev/null +++ b/accessible/mac/mozHTMLAccessible.mm @@ -0,0 +1,141 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozHTMLAccessible.h" + +#import "Accessible-inl.h" +#import "HyperTextAccessible.h" + +#import "nsCocoaUtils.h" + +using namespace mozilla::a11y; + +@implementation mozHeadingAccessible + +- (NSString*)title +{ + nsAutoString title; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + mozilla::ErrorResult rv; + // XXX use the flattening API when there are available + // see bug 768298 + accWrap->GetContent()->GetTextContent(title, rv); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + proxy->Title(title); + } + + return nsCocoaUtils::ToNSString(title); +} + +- (id)value +{ + uint32_t level = 0; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + level = accWrap->GetLevelInternal(); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + level = proxy->GetLevelInternal(); + } + + return [NSNumber numberWithInt:level]; +} + +@end + +@interface mozLinkAccessible () +-(NSURL*)url; +@end + +@implementation mozLinkAccessible + +- (NSArray*)accessibilityAttributeNames +{ + // if we're expired, we don't support any attributes. + if (![self getGeckoAccessible] && ![self getProxyAccessible]) + return [NSArray array]; + + static NSMutableArray* attributes = nil; + + if (!attributes) { + attributes = [[super accessibilityAttributeNames] mutableCopy]; + [attributes addObject:NSAccessibilityURLAttribute]; + } + + return attributes; +} + +- (id)accessibilityAttributeValue:(NSString *)attribute +{ + if ([attribute isEqualToString:NSAccessibilityURLAttribute]) + return [self url]; + + return [super accessibilityAttributeValue:attribute]; +} + +- (NSArray*)accessibilityActionNames +{ + // if we're expired, we don't support any attributes. + if (![self getGeckoAccessible] && ![self getProxyAccessible]) + return [NSArray array]; + + static NSArray* actionNames = nil; + + if (!actionNames) { + actionNames = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, + nil]; + } + + return actionNames; +} + +- (void)accessibilityPerformAction:(NSString*)action +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + if (!accWrap && !proxy) { + return; + } + + if ([action isEqualToString:NSAccessibilityPressAction]) { + if (accWrap) { + accWrap->DoAction(0); + } else if (proxy) { + proxy->DoAction(0); + } + return; + } + + [super accessibilityPerformAction:action]; + +} + +- (NSString*)customDescription +{ + return @""; +} + +- (NSString*)value +{ + return @""; +} + +- (NSURL*)url +{ + nsAutoString value; + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + accWrap->Value(value); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + proxy->Value(value); + } + + NSString* urlString = value.IsEmpty() ? nil : nsCocoaUtils::ToNSString(value); + if (!urlString) + return nil; + + return [NSURL URLWithString:urlString]; +} + +@end diff --git a/accessible/mac/mozTableAccessible.h b/accessible/mac/mozTableAccessible.h new file mode 100644 index 0000000000..435b5adc57 --- /dev/null +++ b/accessible/mac/mozTableAccessible.h @@ -0,0 +1,28 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozAccessible.h" + +@interface mozTablePartAccessible : mozAccessible +- (BOOL)isLayoutTablePart; +- (NSString*)role; +@end + +@interface mozTableAccessible : mozTablePartAccessible +- (NSArray*)additionalAccessibilityAttributeNames; +- (id)accessibilityAttributeValue:(NSString*)attribute; +@end + +@interface mozTableRowAccessible : mozTablePartAccessible +- (NSArray*)additionalAccessibilityAttributeNames; +- (id)accessibilityAttributeValue:(NSString*)attribute; +@end + +@interface mozTableCellAccessible : mozTablePartAccessible +- (NSArray*)additionalAccessibilityAttributeNames; +- (id)accessibilityAttributeValue:(NSString*)attribute; +@end diff --git a/accessible/mac/mozTableAccessible.mm b/accessible/mac/mozTableAccessible.mm new file mode 100644 index 0000000000..6ad157b9f0 --- /dev/null +++ b/accessible/mac/mozTableAccessible.mm @@ -0,0 +1,281 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "Accessible-inl.h" +#import "mozTableAccessible.h" +#import "TableAccessible.h" +#import "TableCellAccessible.h" +#import "nsCocoaUtils.h" + +using namespace mozilla::a11y; + +// convert an array of Gecko accessibles to an NSArray of native accessibles +static inline NSMutableArray* +ConvertToNSArray(nsTArray& aArray) +{ + NSMutableArray* nativeArray = [[NSMutableArray alloc] init]; + + // iterate through the list, and get each native accessible. + size_t totalCount = aArray.Length(); + for (size_t i = 0; i < totalCount; i++) { + Accessible* curAccessible = aArray.ElementAt(i); + mozAccessible* curNative = GetNativeFromGeckoAccessible(curAccessible); + if (curNative) + [nativeArray addObject:GetObjectOrRepresentedView(curNative)]; + } + + return nativeArray; +} + +// convert an array of Gecko proxy accessibles to an NSArray of native accessibles +static inline NSMutableArray* +ConvertToNSArray(nsTArray& aArray) +{ + NSMutableArray* nativeArray = [[NSMutableArray alloc] init]; + + // iterate through the list, and get each native accessible. + size_t totalCount = aArray.Length(); + for (size_t i = 0; i < totalCount; i++) { + ProxyAccessible* curAccessible = aArray.ElementAt(i); + mozAccessible* curNative = GetNativeFromProxy(curAccessible); + if (curNative) + [nativeArray addObject:GetObjectOrRepresentedView(curNative)]; + } + + return nativeArray; +} + +@implementation mozTablePartAccessible +- (BOOL)isLayoutTablePart; +{ + if (Accessible* accWrap = [self getGeckoAccessible]) { + while (accWrap) { + if (accWrap->IsTable()) { + return accWrap->AsTable()->IsProbablyLayoutTable(); + } + accWrap = accWrap->Parent(); + } + return false; + } + + if (ProxyAccessible* proxy = [self getProxyAccessible]) { + while (proxy) { + if (proxy->IsTable()) { + return proxy->TableIsProbablyForLayout(); + } + proxy = proxy->Parent(); + } + } + + return false; +} + +- (NSString*)role +{ + return [self isLayoutTablePart] ? NSAccessibilityGroupRole : [super role]; +} +@end + +@implementation mozTableAccessible +- (NSArray*)additionalAccessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames]; + if ([self isLayoutTablePart]) { + return additionalAttributes; + } + + static NSArray* tableAttrs = nil; + if (!tableAttrs) { + NSMutableArray* tempArray = [NSMutableArray new]; + [tempArray addObject:NSAccessibilityRowCountAttribute]; + [tempArray addObject:NSAccessibilityColumnCountAttribute]; + [tempArray addObject:NSAccessibilityRowsAttribute]; + tableAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + + return [additionalAttributes arrayByAddingObjectsFromArray:tableAttrs]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + TableAccessible* table = accWrap->AsTable(); + if ([attribute isEqualToString:NSAccessibilityRowCountAttribute]) + return @(table->RowCount()); + if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute]) + return @(table->ColCount()); + if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) { + // Create a new array with the list of table rows. + NSMutableArray* nativeArray = [[NSMutableArray alloc] init]; + uint32_t totalCount = accWrap->ChildCount(); + for (uint32_t i = 0; i < totalCount; i++) { + if (accWrap->GetChildAt(i)->IsTableRow()) { + mozAccessible* curNative = + GetNativeFromGeckoAccessible(accWrap->GetChildAt(i)); + if (curNative) + [nativeArray addObject:GetObjectOrRepresentedView(curNative)]; + } + } + return nativeArray; + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if ([attribute isEqualToString:NSAccessibilityRowCountAttribute]) + return @(proxy->TableRowCount()); + if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute]) + return @(proxy->TableColumnCount()); + if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) { + // Create a new array with the list of table rows. + NSMutableArray* nativeArray = [[NSMutableArray alloc] init]; + uint32_t totalCount = proxy->ChildrenCount(); + for (uint32_t i = 0; i < totalCount; i++) { + if (proxy->ChildAt(i)->IsTableRow()) { + mozAccessible* curNative = + GetNativeFromProxy(proxy->ChildAt(i)); + if (curNative) + [nativeArray addObject:GetObjectOrRepresentedView(curNative)]; + } + } + return nativeArray; + } + } + + return [super accessibilityAttributeValue:attribute]; +} +@end + +@implementation mozTableRowAccessible +- (NSArray*)additionalAccessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames]; + if ([self isLayoutTablePart]) { + return additionalAttributes; + } + + static NSArray* tableRowAttrs = nil; + if (!tableRowAttrs) { + NSMutableArray* tempArray = [NSMutableArray new]; + [tempArray addObject:NSAccessibilityIndexAttribute]; + tableRowAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + + return [additionalAttributes arrayByAddingObjectsFromArray:tableRowAttrs]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) { + // Count the number of rows before that one to obtain the row index. + uint32_t index = 0; + Accessible* parent = accWrap->Parent(); + if (parent) { + for (int32_t i = accWrap->IndexInParent() - 1; i >= 0; i--) { + if (parent->GetChildAt(i)->IsTableRow()) { + index++; + } + } + } + return [NSNumber numberWithUnsignedInteger:index]; + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) { + // Count the number of rows before that one to obtain the row index. + uint32_t index = 0; + ProxyAccessible* parent = proxy->Parent(); + if (parent) { + for (int32_t i = proxy->IndexInParent() - 1; i >= 0; i--) { + if (parent->ChildAt(i)->IsTableRow()) { + index++; + } + } + } + return [NSNumber numberWithUnsignedInteger:index]; + } + } + + return [super accessibilityAttributeValue:attribute]; +} +@end + +@implementation mozTableCellAccessible +- (NSArray*)additionalAccessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + NSArray* additionalAttributes = [super additionalAccessibilityAttributeNames]; + if ([self isLayoutTablePart]) { + return additionalAttributes; + } + + static NSArray* tableCellAttrs = nil; + if (!tableCellAttrs) { + NSMutableArray* tempArray = [NSMutableArray new]; + [tempArray addObject:NSAccessibilityRowIndexRangeAttribute]; + [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute]; + [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute]; + [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute]; + tableCellAttrs = [[NSArray alloc] initWithArray:tempArray]; + [tempArray release]; + } + + return [additionalAttributes arrayByAddingObjectsFromArray:tableCellAttrs]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + TableCellAccessible* cell = accWrap->AsTableCell(); + if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute]) + return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(), + cell->RowExtent())]; + if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) + return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(), + cell->ColExtent())]; + if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) { + AutoTArray headerCells; + cell->RowHeaderCells(&headerCells); + return ConvertToNSArray(headerCells); + } + if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) { + AutoTArray headerCells; + cell->ColHeaderCells(&headerCells); + return ConvertToNSArray(headerCells); + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute]) + return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(), + proxy->RowExtent())]; + if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) + return [NSValue valueWithRange:NSMakeRange(proxy->ColIdx(), + proxy->ColExtent())]; + if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) { + nsTArray headerCells; + proxy->RowHeaderCells(&headerCells); + return ConvertToNSArray(headerCells); + } + if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) { + nsTArray headerCells; + proxy->ColHeaderCells(&headerCells); + return ConvertToNSArray(headerCells); + } + } + + return [super accessibilityAttributeValue:attribute]; +} +@end diff --git a/accessible/mac/mozTextAccessible.h b/accessible/mac/mozTextAccessible.h new file mode 100644 index 0000000000..8bc23ae8d5 --- /dev/null +++ b/accessible/mac/mozTextAccessible.h @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "mozAccessible.h" + +#import "HyperTextAccessible.h" + +@interface mozTextAccessible : mozAccessible +{ +} +@end + +@interface mozTextLeafAccessible : mozAccessible +{ +} +@end diff --git a/accessible/mac/mozTextAccessible.mm b/accessible/mac/mozTextAccessible.mm new file mode 100644 index 0000000000..1f433b802e --- /dev/null +++ b/accessible/mac/mozTextAccessible.mm @@ -0,0 +1,627 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Accessible-inl.h" +#include "HyperTextAccessible-inl.h" +#include "TextLeafAccessible.h" + +#include "nsCocoaUtils.h" +#include "nsObjCExceptions.h" + +#import "mozTextAccessible.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +inline bool +ToNSRange(id aValue, NSRange* aRange) +{ + NS_PRECONDITION(aRange, "aRange is nil"); + + if ([aValue isKindOfClass:[NSValue class]] && + strcmp([(NSValue*)aValue objCType], @encode(NSRange)) == 0) { + *aRange = [aValue rangeValue]; + return true; + } + + return false; +} + +inline NSString* +ToNSString(id aValue) +{ + if ([aValue isKindOfClass:[NSString class]]) { + return aValue; + } + + return nil; +} + +@interface mozTextAccessible () +- (NSString*)subrole; +- (NSString*)selectedText; +- (NSValue*)selectedTextRange; +- (NSValue*)visibleCharacterRange; +- (long)textLength; +- (BOOL)isReadOnly; +- (NSNumber*)caretLineNumber; +- (void)setText:(NSString*)newText; +- (NSString*)text; +- (NSString*)stringFromRange:(NSRange*)range; +@end + +@implementation mozTextAccessible + +- (BOOL)accessibilityIsIgnored +{ + return ![self getGeckoAccessible] && ![self getProxyAccessible]; +} + +- (NSArray*)accessibilityAttributeNames +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + static NSMutableArray* supportedAttributes = nil; + if (!supportedAttributes) { + // text-specific attributes to supplement the standard one + supportedAttributes = [[NSMutableArray alloc] initWithObjects: + NSAccessibilitySelectedTextAttribute, // required + NSAccessibilitySelectedTextRangeAttribute, // required + NSAccessibilityNumberOfCharactersAttribute, // required + NSAccessibilityVisibleCharacterRangeAttribute, // required + NSAccessibilityInsertionPointLineNumberAttribute, + @"AXRequired", + @"AXInvalid", + nil + ]; + [supportedAttributes addObjectsFromArray:[super accessibilityAttributeNames]]; + } + return supportedAttributes; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute]) + return [NSNumber numberWithInt:[self textLength]]; + + if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) + return [self caretLineNumber]; + + if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) + return [self selectedTextRange]; + + if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) + return [self selectedText]; + + if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) + return @""; + + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + // Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText + // object's AXSelectedText attribute. See bug 674612 for details. + // Also if there is no selected text, we return the full text. + // See bug 369710 for details. + if ([[self role] isEqualToString:NSAccessibilityStaticTextRole]) { + NSString* selectedText = [self selectedText]; + return (selectedText && [selectedText length]) ? selectedText : [self text]; + } + + return [self text]; + } + + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + if ([attribute isEqualToString:@"AXRequired"]) { + return [NSNumber numberWithBool:!!(accWrap->State() & states::REQUIRED)]; + } + + if ([attribute isEqualToString:@"AXInvalid"]) { + return [NSNumber numberWithBool:!!(accWrap->State() & states::INVALID)]; + } + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + if ([attribute isEqualToString:@"AXRequired"]) { + return [NSNumber numberWithBool:!!(proxy->State() & states::REQUIRED)]; + } + + if ([attribute isEqualToString:@"AXInvalid"]) { + return [NSNumber numberWithBool:!!(proxy->State() & states::INVALID)]; + } + } + + if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) + return [self visibleCharacterRange]; + + // let mozAccessible handle all other attributes + return [super accessibilityAttributeValue:attribute]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSArray*)accessibilityParameterizedAttributeNames +{ + static NSArray* supportedParametrizedAttributes = nil; + // text specific parametrized attributes + if (!supportedParametrizedAttributes) { + supportedParametrizedAttributes = [[NSArray alloc] initWithObjects: + NSAccessibilityStringForRangeParameterizedAttribute, + NSAccessibilityLineForIndexParameterizedAttribute, + NSAccessibilityRangeForLineParameterizedAttribute, + NSAccessibilityAttributedStringForRangeParameterizedAttribute, + NSAccessibilityBoundsForRangeParameterizedAttribute, +#if DEBUG + NSAccessibilityRangeForPositionParameterizedAttribute, + NSAccessibilityRangeForIndexParameterizedAttribute, + NSAccessibilityRTFForRangeParameterizedAttribute, + NSAccessibilityStyleRangeForIndexParameterizedAttribute, +#endif + nil + ]; + } + return supportedParametrizedAttributes; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return nil; + + if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) { + NSRange range; + if (!ToNSRange(parameter, &range)) { +#if DEBUG + NSLog(@"%@: range not set", attribute); +#endif + return @""; + } + + return [self stringFromRange:&range]; + } + + if ([attribute isEqualToString:NSAccessibilityRangeForLineParameterizedAttribute]) { + // XXX: actually get the integer value for the line # + return [NSValue valueWithRange:NSMakeRange(0, [self textLength])]; + } + + if ([attribute isEqualToString:NSAccessibilityAttributedStringForRangeParameterizedAttribute]) { + NSRange range; + if (!ToNSRange(parameter, &range)) { +#if DEBUG + NSLog(@"%@: range not set", attribute); +#endif + return @""; + } + + return [[[NSAttributedString alloc] initWithString:[self stringFromRange:&range]] autorelease]; + } + + if ([attribute isEqualToString:NSAccessibilityLineForIndexParameterizedAttribute]) { + // XXX: actually return the line # + return [NSNumber numberWithInt:0]; + } + + if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) { + NSRange range; + if (!ToNSRange(parameter, &range)) { +#if DEBUG + NSLog(@"%@:no range", attribute); +#endif + return nil; + } + + int32_t start = range.location; + int32_t end = start + range.length; + DesktopIntRect bounds; + if (textAcc) { + bounds = + DesktopIntRect::FromUnknownRect(textAcc->TextBounds(start, end)); + } else if (proxy) { + bounds = + DesktopIntRect::FromUnknownRect(proxy->TextBounds(start, end)); + } + + return [NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(bounds)]; + } + +#if DEBUG + NSLog(@"unhandled attribute:%@ forParameter:%@", attribute, parameter); +#endif + + return nil; +} + +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) + return ![self isReadOnly]; + + if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute] || + [attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute] || + [attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) + return YES; + + return [super accessibilityIsAttributeSettable:attribute]; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); +} + +- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return; + + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + [self setText:ToNSString(value)]; + + return; + } + + if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { + NSString* stringValue = ToNSString(value); + if (!stringValue) + return; + + int32_t start = 0, end = 0; + nsString text; + if (textAcc) { + textAcc->SelectionBoundsAt(0, &start, &end); + textAcc->DeleteText(start, end - start); + nsCocoaUtils::GetStringForNSString(stringValue, text); + textAcc->InsertText(text, start); + } else if (proxy) { + nsString data; + proxy->SelectionBoundsAt(0, data, &start, &end); + proxy->DeleteText(start, end - start); + nsCocoaUtils::GetStringForNSString(stringValue, text); + proxy->InsertText(text, start); + } + } + + if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { + NSRange range; + if (!ToNSRange(value, &range)) + return; + + if (textAcc) { + textAcc->SetSelectionBoundsAt(0, range.location, + range.location + range.length); + } else if (proxy) { + proxy->SetSelectionBoundsAt(0, range.location, + range.location + range.length); + } + return; + } + + if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) { + NSRange range; + if (!ToNSRange(value, &range)) + return; + + if (textAcc) { + textAcc->ScrollSubstringTo(range.location, range.location + range.length, + nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE); + } else if (proxy) { + proxy->ScrollSubstringTo(range.location, range.location + range.length, + nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE); + } + return; + } + + [super accessibilitySetValue:value forAttribute:attribute]; + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (NSString*)subrole +{ + if(mRole == roles::PASSWORD_TEXT) + return NSAccessibilitySecureTextFieldSubrole; + + return nil; +} + +#pragma mark - + +- (BOOL)isReadOnly +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + if ([[self role] isEqualToString:NSAccessibilityStaticTextRole]) + return YES; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (textAcc) + return (accWrap->State() & states::READONLY) == 0; + + if (ProxyAccessible* proxy = [self getProxyAccessible]) + return (proxy->State() & states::READONLY) == 0; + + return NO; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); +} + +- (NSNumber*)caretLineNumber +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + + int32_t lineNumber = -1; + if (textAcc) { + lineNumber = textAcc->CaretLineNumber() - 1; + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + lineNumber = proxy->CaretLineNumber() - 1; + } + + return (lineNumber >= 0) ? [NSNumber numberWithInt:lineNumber] : nil; +} + +- (void)setText:(NSString*)aNewString +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + + nsString text; + nsCocoaUtils::GetStringForNSString(aNewString, text); + if (textAcc) { + textAcc->ReplaceText(text); + } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { + proxy->ReplaceText(text); + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (NSString*)text +{ + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return nil; + + // A password text field returns an empty value + if (mRole == roles::PASSWORD_TEXT) + return @""; + + nsAutoString text; + if (textAcc) { + textAcc->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text); + } else if (proxy) { + proxy->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text); + } + + return nsCocoaUtils::ToNSString(text); +} + +- (long)textLength +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return 0; + + return textAcc ? textAcc->CharacterCount() : proxy->CharacterCount(); + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0); +} + +- (long)selectedTextLength +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return 0; + + int32_t start = 0, end = 0; + if (textAcc) { + textAcc->SelectionBoundsAt(0, &start, &end); + } else if (proxy) { + nsString data; + proxy->SelectionBoundsAt(0, data, &start, &end); + } + return (end - start); + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0); +} + +- (NSString*)selectedText +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return nil; + + int32_t start = 0, end = 0; + nsAutoString selText; + if (textAcc) { + textAcc->SelectionBoundsAt(0, &start, &end); + if (start != end) { + textAcc->TextSubstring(start, end, selText); + } + } else if (proxy) { + proxy->SelectionBoundsAt(0, selText, &start, &end); + } + + return nsCocoaUtils::ToNSString(selText); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSValue*)selectedTextRange +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + + int32_t start = 0; + int32_t end = 0; + int32_t count = 0; + if (textAcc) { + count = textAcc->SelectionCount(); + if (count) { + textAcc->SelectionBoundsAt(0, &start, &end); + return [NSValue valueWithRange:NSMakeRange(start, end - start)]; + } + + start = textAcc->CaretOffset(); + return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)]; + } + + if (proxy) { + count = proxy->SelectionCount(); + if (count) { + nsString data; + proxy->SelectionBoundsAt(0, data, &start, &end); + return [NSValue valueWithRange:NSMakeRange(start, end - start)]; + } + + start = proxy->CaretOffset(); + return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)]; + } + + return [NSValue valueWithRange:NSMakeRange(0, 0)]; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +- (NSValue*)visibleCharacterRange +{ + // XXX this won't work with Textarea and such as we actually don't give + // the visible character range. + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return 0; + + return [NSValue valueWithRange: + NSMakeRange(0, textAcc ? + textAcc->CharacterCount() : proxy->CharacterCount())]; +} + +- (void)valueDidChange +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + NSAccessibilityPostNotification(GetObjectOrRepresentedView(self), + NSAccessibilityValueChangedNotification); + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +- (void)selectedTextDidChange +{ + NSAccessibilityPostNotification(GetObjectOrRepresentedView(self), + NSAccessibilitySelectedTextChangedNotification); +} + +- (NSString*)stringFromRange:(NSRange*)range +{ + NS_PRECONDITION(range, "no range"); + + AccessibleWrap* accWrap = [self getGeckoAccessible]; + ProxyAccessible* proxy = [self getProxyAccessible]; + HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr; + if (!textAcc && !proxy) + return nil; + + nsAutoString text; + if (textAcc) { + textAcc->TextSubstring(range->location, + range->location + range->length, text); + } else if (proxy) { + proxy->TextSubstring(range->location, + range->location + range->length, text); + } + + return nsCocoaUtils::ToNSString(text); +} + +@end + +@implementation mozTextLeafAccessible + +- (NSArray*)accessibilityAttributeNames +{ + static NSMutableArray* supportedAttributes = nil; + if (!supportedAttributes) { + supportedAttributes = [[super accessibilityAttributeNames] mutableCopy]; + [supportedAttributes removeObject:NSAccessibilityChildrenAttribute]; + } + + return supportedAttributes; +} + +- (id)accessibilityAttributeValue:(NSString*)attribute +{ + if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) + return @""; + + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) + return [self text]; + + return [super accessibilityAttributeValue:attribute]; +} + +- (NSString*)text +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + return nsCocoaUtils::ToNSString(accWrap->AsTextLeaf()->Text()); + } + + if (ProxyAccessible* proxy = [self getProxyAccessible]) { + nsString text; + proxy->Text(&text); + return nsCocoaUtils::ToNSString(text); + } + + return nil; +} + +- (long)textLength +{ + if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { + return accWrap->AsTextLeaf()->Text().Length(); + } + + if (ProxyAccessible* proxy = [self getProxyAccessible]) { + nsString text; + proxy->Text(&text); + return text.Length(); + } + + return 0; +} + +@end diff --git a/accessible/moz.build b/accessible/moz.build index edfd88f504..aa1cccb982 100644 --- a/accessible/moz.build +++ b/accessible/moz.build @@ -9,6 +9,8 @@ if 'gtk' in toolkit: DIRS += ['atk'] elif toolkit == 'windows': DIRS += ['windows'] +elif toolkit == 'cocoa': + DIRS += ['mac'] else: DIRS += ['other'] diff --git a/accessible/xpcom/moz.build b/accessible/xpcom/moz.build index 5d1ad16884..d43efd06d0 100644 --- a/accessible/xpcom/moz.build +++ b/accessible/xpcom/moz.build @@ -42,6 +42,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += [ '/accessible/windows/msaa', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/accessible/xul/moz.build b/accessible/xul/moz.build index b04c35dc40..54182c0975 100644 --- a/accessible/xul/moz.build +++ b/accessible/xul/moz.build @@ -37,6 +37,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': '/accessible/windows/ia2', '/accessible/windows/msaa', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/accessible/mac', + ] else: LOCAL_INCLUDES += [ '/accessible/other', diff --git a/db/sqlite3/src/moz.build b/db/sqlite3/src/moz.build index 327e77677a..1ffc326f8a 100644 --- a/db/sqlite3/src/moz.build +++ b/db/sqlite3/src/moz.build @@ -45,6 +45,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': DEFINES['SQLITE_WIN32_GETVERSIONEX'] = 0 DEFINES['SQLITE_ALLOW_URI_AUTHORITY'] = 1 +# -DSQLITE_ENABLE_LOCKING_STYLE=1 to help with AFP folders +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DEFINES['SQLITE_ENABLE_LOCKING_STYLE'] = 1 + # sqlite defaults this to on on __APPLE_ but it breaks on newer iOS SDKs if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit': DEFINES['SQLITE_ENABLE_LOCKING_STYLE'] = 0 diff --git a/embedding/components/build/moz.build b/embedding/components/build/moz.build index c66f0c79ee..361fd8768a 100644 --- a/embedding/components/build/moz.build +++ b/embedding/components/build/moz.build @@ -22,6 +22,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += [ '../printingui/win', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DEFINES['PROXY_PRINTING'] = 1 + LOCAL_INCLUDES += [ + '../printingui/mac', + ] if CONFIG['MOZ_PDF_PRINTING']: DEFINES['PROXY_PRINTING'] = 1 diff --git a/embedding/components/printingui/mac/moz.build b/embedding/components/printingui/mac/moz.build new file mode 100644 index 0000000000..c2fe2f4731 --- /dev/null +++ b/embedding/components/printingui/mac/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsPrintProgress.cpp', + 'nsPrintProgressParams.cpp', +] + +SOURCES += [ + 'nsPrintingPromptServiceX.mm', +] + +FINAL_LIBRARY = 'xul' diff --git a/embedding/components/printingui/mac/nsPrintProgress.cpp b/embedding/components/printingui/mac/nsPrintProgress.cpp new file mode 100644 index 0000000000..0ae0a63d9a --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintProgress.cpp @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintProgress.h" + +#include "nsIBaseWindow.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsIComponentManager.h" +#include "nsPIDOMWindow.h" + +NS_IMPL_ADDREF(nsPrintProgress) +NS_IMPL_RELEASE(nsPrintProgress) + +NS_INTERFACE_MAP_BEGIN(nsPrintProgress) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrintStatusFeedback) + NS_INTERFACE_MAP_ENTRY(nsIPrintProgress) + NS_INTERFACE_MAP_ENTRY(nsIPrintStatusFeedback) + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) +NS_INTERFACE_MAP_END_THREADSAFE + + +nsPrintProgress::nsPrintProgress() +{ + m_closeProgress = false; + m_processCanceled = false; + m_pendingStateFlags = -1; + m_pendingStateValue = NS_OK; +} + +nsPrintProgress::~nsPrintProgress() +{ + (void)ReleaseListeners(); +} + +NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(mozIDOMWindowProxy *parent, + const char *dialogURL, + nsISupports *parameters, + nsIObserver *openDialogObserver, + bool *notifyOnOpen) +{ + MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress " + "implementation for OS X returns " + "NS_ERROR_NOT_IMPLEMENTED, so we should never get " + "here."); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose) +{ + MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress " + "implementation for OS X returns " + "NS_ERROR_NOT_IMPLEMENTED, so we should never get " + "here."); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::GetPrompter(nsIPrompt **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nullptr; + + if (! m_closeProgress && m_dialog) { + nsCOMPtr window = do_QueryInterface(m_dialog); + MOZ_ASSERT(window); + return window->GetPrompter(_retval); + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsPrintProgress::GetProcessCanceledByUser(bool *aProcessCanceledByUser) +{ + NS_ENSURE_ARG_POINTER(aProcessCanceledByUser); + *aProcessCanceledByUser = m_processCanceled; + return NS_OK; +} +NS_IMETHODIMP nsPrintProgress::SetProcessCanceledByUser(bool aProcessCanceledByUser) +{ + m_processCanceled = aProcessCanceledByUser; + OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP, NS_OK); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::RegisterListener(nsIWebProgressListener * listener) +{ + if (!listener) //Nothing to do with a null listener! + return NS_OK; + + m_listenerList.AppendObject(listener); + if (m_closeProgress || m_processCanceled) + listener->OnStateChange(nullptr, nullptr, + nsIWebProgressListener::STATE_STOP, NS_OK); + else + { + listener->OnStatusChange(nullptr, nullptr, NS_OK, m_pendingStatus.get()); + if (m_pendingStateFlags != -1) + listener->OnStateChange(nullptr, nullptr, m_pendingStateFlags, m_pendingStateValue); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::UnregisterListener(nsIWebProgressListener *listener) +{ + if (listener) + m_listenerList.RemoveObject(listener); + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::DoneIniting() +{ + if (m_observer) { + m_observer->Observe(nullptr, nullptr, nullptr); + } + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aStateFlags, nsresult aStatus) +{ + m_pendingStateFlags = aStateFlags; + m_pendingStateValue = aStatus; + + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnStateChange(aWebProgress, aRequest, aStateFlags, aStatus); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) +{ + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, uint32_t aFlags) +{ + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const char16_t *aMessage) +{ + if (aMessage && *aMessage) + m_pendingStatus = aMessage; + + uint32_t count = m_listenerList.Count(); + for (uint32_t i = count - 1; i < count; i --) + { + nsCOMPtr progressListener = m_listenerList.SafeObjectAt(i); + if (progressListener) + progressListener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage); + } + + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t state) +{ + return NS_OK; +} + +nsresult nsPrintProgress::ReleaseListeners() +{ + m_listenerList.Clear(); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgress::ShowStatusString(const char16_t *status) +{ + return OnStatusChange(nullptr, nullptr, NS_OK, status); +} + +NS_IMETHODIMP nsPrintProgress::StartMeteors() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::StopMeteors() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::ShowProgress(int32_t percent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::SetDocShell(nsIDocShell *shell, + mozIDOMWindowProxy *window) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsPrintProgress::CloseWindow() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/embedding/components/printingui/mac/nsPrintProgress.h b/embedding/components/printingui/mac/nsPrintProgress.h new file mode 100644 index 0000000000..938558c3e1 --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintProgress.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintProgress_h +#define __nsPrintProgress_h + +#include "nsIPrintProgress.h" + +#include "nsCOMArray.h" +#include "nsCOMPtr.h" +#include "nsIPrintStatusFeedback.h" +#include "nsIObserver.h" +#include "nsString.h" + +class nsPrintProgress : public nsIPrintProgress, public nsIPrintStatusFeedback +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIPRINTPROGRESS + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_NSIPRINTSTATUSFEEDBACK + + nsPrintProgress(); + +protected: + virtual ~nsPrintProgress(); + +private: + nsresult ReleaseListeners(); + + bool m_closeProgress; + bool m_processCanceled; + nsString m_pendingStatus; + int32_t m_pendingStateFlags; + nsresult m_pendingStateValue; + // XXX This member is read-only. + nsCOMPtr m_dialog; + nsCOMArray m_listenerList; + nsCOMPtr m_observer; +}; + +#endif diff --git a/embedding/components/printingui/mac/nsPrintProgressParams.cpp b/embedding/components/printingui/mac/nsPrintProgressParams.cpp new file mode 100644 index 0000000000..eba86b2987 --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintProgressParams.cpp @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintProgressParams.h" +#include "nsReadableUtils.h" + + +NS_IMPL_ISUPPORTS(nsPrintProgressParams, nsIPrintProgressParams) + +nsPrintProgressParams::nsPrintProgressParams() +{ +} + +nsPrintProgressParams::~nsPrintProgressParams() +{ +} + +NS_IMETHODIMP nsPrintProgressParams::GetDocTitle(char16_t * *aDocTitle) +{ + NS_ENSURE_ARG(aDocTitle); + + *aDocTitle = ToNewUnicode(mDocTitle); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::SetDocTitle(const char16_t * aDocTitle) +{ + mDocTitle = aDocTitle; + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::GetDocURL(char16_t * *aDocURL) +{ + NS_ENSURE_ARG(aDocURL); + + *aDocURL = ToNewUnicode(mDocURL); + return NS_OK; +} + +NS_IMETHODIMP nsPrintProgressParams::SetDocURL(const char16_t * aDocURL) +{ + mDocURL = aDocURL; + return NS_OK; +} + diff --git a/embedding/components/printingui/mac/nsPrintProgressParams.h b/embedding/components/printingui/mac/nsPrintProgressParams.h new file mode 100644 index 0000000000..65c00d98f0 --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintProgressParams.h @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintProgressParams_h +#define __nsPrintProgressParams_h + +#include "nsIPrintProgressParams.h" +#include "nsString.h" + +class nsPrintProgressParams : public nsIPrintProgressParams +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPRINTPROGRESSPARAMS + + nsPrintProgressParams(); + +protected: + virtual ~nsPrintProgressParams(); + +private: + nsString mDocTitle; + nsString mDocURL; +}; + +#endif diff --git a/embedding/components/printingui/mac/nsPrintingPromptService.h b/embedding/components/printingui/mac/nsPrintingPromptService.h new file mode 100644 index 0000000000..0334db2230 --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintingPromptService.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsPrintingPromptService_h +#define __nsPrintingPromptService_h + +// {E042570C-62DE-4bb6-A6E0-798E3C07B4DF} +#define NS_PRINTINGPROMPTSERVICE_CID \ + {0xe042570c, 0x62de, 0x4bb6, { 0xa6, 0xe0, 0x79, 0x8e, 0x3c, 0x7, 0xb4, 0xdf}} +#define NS_PRINTINGPROMPTSERVICE_CONTRACTID \ + "@mozilla.org/embedcomp/printingprompt-service;1" + +#include "nsCOMPtr.h" +#include "nsIPrintingPromptService.h" +#include "nsPIPromptService.h" +#include "nsIWindowWatcher.h" + +// Printing Progress Includes +#include "nsPrintProgress.h" +#include "nsIWebProgressListener.h" + +class nsPrintingPromptService: public nsIPrintingPromptService, + public nsIWebProgressListener +{ +public: + nsPrintingPromptService(); + + nsresult Init(); + + NS_DECL_NSIPRINTINGPROMPTSERVICE + NS_DECL_NSIWEBPROGRESSLISTENER + NS_DECL_ISUPPORTS + +protected: + virtual ~nsPrintingPromptService(); + +private: + nsCOMPtr mPrintProgress; +}; + +#endif diff --git a/embedding/components/printingui/mac/nsPrintingPromptServiceX.mm b/embedding/components/printingui/mac/nsPrintingPromptServiceX.mm new file mode 100644 index 0000000000..3b956100be --- /dev/null +++ b/embedding/components/printingui/mac/nsPrintingPromptServiceX.mm @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPrintingPromptService.h" + +#include "nsCOMPtr.h" +#include "nsServiceManagerUtils.h" +#include "nsObjCExceptions.h" + +#include "nsIPrintingPromptService.h" +#include "nsIFactory.h" +#include "nsIPrintDialogService.h" +#include "nsPIDOMWindow.h" + +//***************************************************************************** +// nsPrintingPromptService +//***************************************************************************** + +NS_IMPL_ISUPPORTS(nsPrintingPromptService, nsIPrintingPromptService, nsIWebProgressListener) + +nsPrintingPromptService::nsPrintingPromptService() +{ +} + +nsPrintingPromptService::~nsPrintingPromptService() +{ +} + +nsresult nsPrintingPromptService::Init() +{ + return NS_OK; +} + +//***************************************************************************** +// nsPrintingPromptService::nsIPrintingPromptService +//***************************************************************************** + +NS_IMETHODIMP +nsPrintingPromptService::ShowPrintDialog(mozIDOMWindowProxy *parent, nsIWebBrowserPrint *webBrowserPrint, nsIPrintSettings *printSettings) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + nsCOMPtr dlgPrint(do_GetService( + NS_PRINTDIALOGSERVICE_CONTRACTID)); + if (dlgPrint) { + return dlgPrint->Show(nsPIDOMWindowOuter::From(parent), printSettings, + webBrowserPrint); + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +nsPrintingPromptService::ShowProgress(mozIDOMWindowProxy* parent, + nsIWebBrowserPrint* webBrowserPrint, // ok to be null + nsIPrintSettings* printSettings, // ok to be null + nsIObserver* openDialogObserver, // ok to be null + bool isForPrinting, + nsIWebProgressListener** webProgressListener, + nsIPrintProgressParams** printProgressParams, + bool* notifyOnOpen) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent, nsIPrintSettings *printSettings, nsIObserver *aObs) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + nsCOMPtr dlgPrint(do_GetService( + NS_PRINTDIALOGSERVICE_CONTRACTID)); + if (dlgPrint) { + return dlgPrint->ShowPageSetup(nsPIDOMWindowOuter::From(parent), printSettings); + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent, const char16_t *printerName, nsIPrintSettings *printSettings) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +//***************************************************************************** +// nsPrintingPromptService::nsIWebProgressListener +//***************************************************************************** + +NS_IMETHODIMP +nsPrintingPromptService::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aStateFlags, nsresult aStatus) +{ + return NS_OK; +} + +/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */ +NS_IMETHODIMP +nsPrintingPromptService::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) +{ + return NS_OK; +} + +/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */ +NS_IMETHODIMP +nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, uint32_t aFlags) +{ + return NS_OK; +} + +/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ +NS_IMETHODIMP +nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const char16_t *aMessage) +{ + return NS_OK; +} + +/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */ +NS_IMETHODIMP +nsPrintingPromptService::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t state) +{ + return NS_OK; +} diff --git a/embedding/components/printingui/moz.build b/embedding/components/printingui/moz.build index e0d6316931..c75471555e 100644 --- a/embedding/components/printingui/moz.build +++ b/embedding/components/printingui/moz.build @@ -10,5 +10,7 @@ DIRS += ['ipc'] if CONFIG['NS_PRINTING']: if toolkit == 'windows': DIRS += ['win'] + elif toolkit == 'cocoa': + DIRS += ['mac'] elif CONFIG['MOZ_PDF_PRINTING']: DIRS += ['unixshared'] diff --git a/gfx/cairo/cairo/src/moz.build b/gfx/cairo/cairo/src/moz.build index 75201123ce..e097c45ca6 100644 --- a/gfx/cairo/cairo/src/moz.build +++ b/gfx/cairo/cairo/src/moz.build @@ -16,7 +16,7 @@ EXPORTS.cairo += [ 'pixman-rename.h', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] not in ('uikit'): +if CONFIG['MOZ_WIDGET_TOOLKIT'] not in ('cocoa', 'uikit'): EXPORTS.cairo += [ 'cairo-pdf.h', ] @@ -53,7 +53,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': ] else: DEFINES['CAIRO_OMIT_WIN32_PRINTING'] = True -elif CONFIG['MOZ_WIDGET_TOOLKIT'] in {'uikit'}: +elif CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}: EXPORTS.cairo += [ 'cairo-quartz-image.h', 'cairo-quartz.h', diff --git a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp new file mode 100644 index 0000000000..8834773e4c --- /dev/null +++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MacIOSurfaceTextureHostBasic.h" +#include "mozilla/gfx/MacIOSurface.h" +#include "MacIOSurfaceHelpers.h" + +namespace mozilla { +namespace layers { + +MacIOSurfaceTextureSourceBasic::MacIOSurfaceTextureSourceBasic( + BasicCompositor* aCompositor, + MacIOSurface* aSurface) + : mCompositor(aCompositor) + , mSurface(aSurface) +{ + MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceBasic); +} + +MacIOSurfaceTextureSourceBasic::~MacIOSurfaceTextureSourceBasic() +{ + MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceBasic); +} + +gfx::IntSize +MacIOSurfaceTextureSourceBasic::GetSize() const +{ + return gfx::IntSize(mSurface->GetDevicePixelWidth(), + mSurface->GetDevicePixelHeight()); +} + +gfx::SurfaceFormat +MacIOSurfaceTextureSourceBasic::GetFormat() const +{ + // Set the format the same way as CreateSourceSurfaceFromMacIOSurface. + return mSurface->GetFormat() == gfx::SurfaceFormat::NV12 + ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8; +} + +MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic( + TextureFlags aFlags, + const SurfaceDescriptorMacIOSurface& aDescriptor +) + : TextureHost(aFlags) +{ + mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(), + aDescriptor.scaleFactor(), + !aDescriptor.isOpaque()); +} + +gfx::SourceSurface* +MacIOSurfaceTextureSourceBasic::GetSurface(gfx::DrawTarget* aTarget) +{ + if (!mSourceSurface) { + mSourceSurface = CreateSourceSurfaceFromMacIOSurface(mSurface); + } + return mSourceSurface; +} + +void +MacIOSurfaceTextureSourceBasic::SetCompositor(Compositor* aCompositor) +{ + mCompositor = AssertBasicCompositor(aCompositor); +} + +bool +MacIOSurfaceTextureHostBasic::Lock() +{ + if (!mCompositor) { + return false; + } + + if (!mTextureSource) { + mTextureSource = new MacIOSurfaceTextureSourceBasic(mCompositor, mSurface); + } + return true; +} + +void +MacIOSurfaceTextureHostBasic::SetCompositor(Compositor* aCompositor) +{ + BasicCompositor* compositor = AssertBasicCompositor(aCompositor); + if (!compositor) { + mTextureSource = nullptr; + return; + } + mCompositor = compositor; + if (mTextureSource) { + mTextureSource->SetCompositor(compositor); + } +} + +gfx::SurfaceFormat +MacIOSurfaceTextureHostBasic::GetFormat() const { + return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8X8; +} + +gfx::IntSize +MacIOSurfaceTextureHostBasic::GetSize() const { + return gfx::IntSize(mSurface->GetDevicePixelWidth(), + mSurface->GetDevicePixelHeight()); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h new file mode 100644 index 0000000000..7949aecfca --- /dev/null +++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_MACIOSURFACETEXTUREHOST_BASIC_H +#define MOZILLA_GFX_MACIOSURFACETEXTUREHOST_BASIC_H + +#include "mozilla/layers/BasicCompositor.h" +#include "mozilla/layers/TextureHostBasic.h" + +class MacIOSurface; + +namespace mozilla { +namespace layers { + +class BasicCompositor; + +/** + * A texture source meant for use with BasicCompositor. + * + * It does not own any GL texture, and attaches its shared handle to one of + * the compositor's temporary textures when binding. + */ +class MacIOSurfaceTextureSourceBasic + : public TextureSourceBasic, + public TextureSource +{ +public: + MacIOSurfaceTextureSourceBasic(BasicCompositor* aCompositor, + MacIOSurface* aSurface); + virtual ~MacIOSurfaceTextureSourceBasic(); + + virtual const char* Name() const override { return "MacIOSurfaceTextureSourceBasic"; } + + virtual TextureSourceBasic* AsSourceBasic() override { return this; } + + virtual gfx::IntSize GetSize() const override; + virtual gfx::SurfaceFormat GetFormat() const override; + virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) override; + + virtual void DeallocateDeviceData() override { } + + virtual void SetCompositor(Compositor* aCompositor) override; + +protected: + RefPtr mCompositor; + RefPtr mSurface; + RefPtr mSourceSurface; +}; + +/** + * A TextureHost for shared MacIOSurface + * + * Most of the logic actually happens in MacIOSurfaceTextureSourceBasic. + */ +class MacIOSurfaceTextureHostBasic : public TextureHost +{ +public: + MacIOSurfaceTextureHostBasic(TextureFlags aFlags, + const SurfaceDescriptorMacIOSurface& aDescriptor); + + virtual void SetCompositor(Compositor* aCompositor) override; + + virtual Compositor* GetCompositor() override { return mCompositor; } + + virtual bool Lock() override; + + virtual gfx::SurfaceFormat GetFormat() const override; + + virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override + { + aTexture = mTextureSource; + return !!aTexture; + } + + virtual already_AddRefed GetAsSurface() override + { + return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING) + } + + virtual gfx::IntSize GetSize() const override; + +#ifdef MOZ_LAYERS_HAVE_LOG + virtual const char* Name() override { return "MacIOSurfaceTextureHostBasic"; } +#endif + +protected: + RefPtr mCompositor; + RefPtr mTextureSource; + RefPtr mSurface; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_BASIC_H diff --git a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp new file mode 100644 index 0000000000..cc5199ea82 --- /dev/null +++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=8 et : + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/gfx/Point.h" +#include "mozilla/layers/PLayerTransaction.h" +#include "mozilla/layers/ShadowLayers.h" +#include "mozilla/layers/LayerManagerComposite.h" +#include "mozilla/layers/CompositorTypes.h" + +#include "gfx2DGlue.h" +#include "gfxPlatform.h" + +using namespace mozilla::gl; + +namespace mozilla { +namespace layers { + +/*static*/ void +ShadowLayerForwarder::PlatformSyncBeforeUpdate() +{ +} + +/*static*/ void +LayerManagerComposite::PlatformSyncBeforeReplyUpdate() +{ +} + +/*static*/ bool +LayerManagerComposite::SupportsDirectTexturing() +{ + return false; +} + + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 50c2b8f855..be0c95ba20 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -104,6 +104,7 @@ EXPORTS.mozilla.layers += [ 'AxisPhysicsModel.h', 'AxisPhysicsMSDModel.h', 'basic/BasicCompositor.h', + 'basic/MacIOSurfaceTextureHostBasic.h', 'basic/TextureHostBasic.h', 'BSPTree.h', 'BufferTexture.h', @@ -172,6 +173,8 @@ EXPORTS.mozilla.layers += [ 'LayersTypes.h', 'opengl/CompositingRenderTargetOGL.h', 'opengl/CompositorOGL.h', + 'opengl/MacIOSurfaceTextureClientOGL.h', + 'opengl/MacIOSurfaceTextureHostOGL.h', 'opengl/TextureClientOGL.h', 'opengl/TextureHostOGL.h', 'PersistentBufferProvider.h', @@ -197,6 +200,21 @@ if CONFIG['MOZ_X11']: 'opengl/X11TextureSourceOGL.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + EXPORTS.mozilla.layers += [ + 'opengl/GLManager.h', + ] + EXPORTS += [ + 'MacIOSurfaceHelpers.h', + 'MacIOSurfaceImage.h', + ] + SOURCES += [ + 'ipc/ShadowLayerUtilsMac.cpp', + 'MacIOSurfaceHelpers.cpp', + 'MacIOSurfaceImage.cpp', + 'opengl/GLManager.cpp', + ] + SOURCES += [ 'apz/public/IAPZCTreeManager.cpp', 'apz/src/APZCTreeManager.cpp', @@ -348,6 +366,13 @@ if CONFIG['_MSC_VER'] and CONFIG['CPU_ARCH'] == 'x86_64': ]: SOURCES[src].no_pgo = True +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'basic/MacIOSurfaceTextureHostBasic.cpp', + 'opengl/MacIOSurfaceTextureClientOGL.cpp', + 'opengl/MacIOSurfaceTextureHostOGL.cpp', + ] + IPDL_SOURCES = [ 'ipc/LayersMessages.ipdlh', 'ipc/LayersSurfaces.ipdlh', diff --git a/gfx/layers/opengl/GLManager.cpp b/gfx/layers/opengl/GLManager.cpp new file mode 100644 index 0000000000..e4c0b361fb --- /dev/null +++ b/gfx/layers/opengl/GLManager.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GLManager.h" +#include "CompositorOGL.h" // for CompositorOGL +#include "GLContext.h" // for GLContext +#include "mozilla/Attributes.h" // for override +#include "mozilla/RefPtr.h" // for RefPtr +#include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/LayerManagerComposite.h" +#include "mozilla/layers/LayersTypes.h" +#include "mozilla/mozalloc.h" // for operator new, etc + +using namespace mozilla::gl; + +namespace mozilla { +namespace layers { + +class GLManagerCompositor : public GLManager +{ +public: + explicit GLManagerCompositor(CompositorOGL* aCompositor) + : mImpl(aCompositor) + {} + + virtual GLContext* gl() const override + { + return mImpl->gl(); + } + + virtual void ActivateProgram(ShaderProgramOGL *aProg) override + { + mImpl->ActivateProgram(aProg); + } + + virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) override + { + ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(aTarget, aFormat); + return mImpl->GetShaderProgramFor(config); + } + + virtual const gfx::Matrix4x4& GetProjMatrix() const override + { + return mImpl->GetProjMatrix(); + } + + virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, + const gfx::Rect& aLayerRect, + const gfx::Rect& aTextureRect) override + { + mImpl->BindAndDrawQuad(aProg, aLayerRect, aTextureRect); + } + +private: + RefPtr mImpl; +}; + +/* static */ GLManager* +GLManager::CreateGLManager(LayerManagerComposite* aManager) +{ + if (aManager && aManager->GetCompositor()->GetBackendType() == LayersBackend::LAYERS_OPENGL) { + return new GLManagerCompositor(aManager->GetCompositor()->AsCompositorOGL()); + } + return nullptr; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/opengl/GLManager.h b/gfx/layers/opengl/GLManager.h new file mode 100644 index 0000000000..7c872758e9 --- /dev/null +++ b/gfx/layers/opengl/GLManager.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_GLMANAGER_H +#define MOZILLA_GFX_GLMANAGER_H + +#include "mozilla/gfx/Types.h" // for SurfaceFormat +#include "OGLShaderProgram.h" + +namespace mozilla { +namespace gl { +class GLContext; +} // namespace gl + +namespace layers { + +class LayerManagerComposite; + +/** + * Minimal interface to allow widgets to draw using OpenGL. Abstracts + * CompositorOGL. Call CreateGLManager with a LayerManagerComposite + * backed by a CompositorOGL. + */ +class GLManager +{ +public: + static GLManager* CreateGLManager(LayerManagerComposite* aManager); + + virtual ~GLManager() {} + + virtual gl::GLContext* gl() const = 0; + virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0; + virtual void ActivateProgram(ShaderProgramOGL* aPrg) = 0; + virtual const gfx::Matrix4x4& GetProjMatrix() const = 0; + virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aLayerRect, + const gfx::Rect& aTextureRect) = 0; +}; + +} // namespace layers +} // namespace mozilla + +#endif diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp new file mode 100644 index 0000000000..dd522e6503 --- /dev/null +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MacIOSurfaceTextureClientOGL.h" +#include "mozilla/gfx/MacIOSurface.h" +#include "MacIOSurfaceHelpers.h" +#include "gfxPlatform.h" + +namespace mozilla { +namespace layers { + +using namespace gfx; + +MacIOSurfaceTextureData::MacIOSurfaceTextureData(MacIOSurface* aSurface, + BackendType aBackend) + : mSurface(aSurface) + , mBackend(aBackend) +{ + MOZ_ASSERT(mSurface); +} + +MacIOSurfaceTextureData::~MacIOSurfaceTextureData() +{} + +// static +MacIOSurfaceTextureData* +MacIOSurfaceTextureData::Create(MacIOSurface* aSurface, BackendType aBackend) +{ + MOZ_ASSERT(aSurface); + if (!aSurface) { + return nullptr; + } + return new MacIOSurfaceTextureData(aSurface, aBackend); +} + +MacIOSurfaceTextureData* +MacIOSurfaceTextureData::Create(const IntSize& aSize, + SurfaceFormat aFormat, + BackendType aBackend) +{ + if (aFormat != SurfaceFormat::B8G8R8A8 && + aFormat != SurfaceFormat::B8G8R8X8) { + return nullptr; + } + + RefPtr surf = MacIOSurface::CreateIOSurface(aSize.width, aSize.height, + 1.0, + aFormat == SurfaceFormat::B8G8R8A8); + if (!surf) { + return nullptr; + } + + return Create(surf, aBackend); +} + +bool +MacIOSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) +{ + aOutDescriptor = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(), + mSurface->GetContentsScaleFactor(), + !mSurface->HasAlpha()); + return true; +} + +void +MacIOSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const +{ + aInfo.size = gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight()); + aInfo.format = mSurface->HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8; + aInfo.hasIntermediateBuffer = false; + aInfo.hasSynchronization = false; + aInfo.supportsMoz2D = true; + aInfo.canExposeMappedData = false; +} + +bool +MacIOSurfaceTextureData::Lock(OpenMode) +{ + mSurface->Lock(false); + return true; +} + +void +MacIOSurfaceTextureData::Unlock() +{ + mSurface->Unlock(false); +} + +already_AddRefed +MacIOSurfaceTextureData::GetAsSurface() +{ + RefPtr surf = CreateSourceSurfaceFromMacIOSurface(mSurface); + return surf->GetDataSurface(); +} + +already_AddRefed +MacIOSurfaceTextureData::BorrowDrawTarget() +{ + MOZ_ASSERT(mBackend != BackendType::NONE); + if (mBackend == BackendType::NONE) { + // shouldn't happen, but degrade gracefully + return nullptr; + } + return Factory::CreateDrawTargetForData( + mBackend, + (unsigned char*)mSurface->GetBaseAddress(), + IntSize(mSurface->GetWidth(), mSurface->GetHeight()), + mSurface->GetBytesPerRow(), + mSurface->HasAlpha() ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8, + true); +} + +void +MacIOSurfaceTextureData::Deallocate(LayersIPCChannel*) +{ + mSurface = nullptr; +} + +void +MacIOSurfaceTextureData::Forget(LayersIPCChannel*) +{ + mSurface = nullptr; +} + +bool +MacIOSurfaceTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) +{ + RefPtr dt = BorrowDrawTarget(); + if (!dt) { + return false; + } + + dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint()); + return true; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h new file mode 100644 index 0000000000..21e4459537 --- /dev/null +++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H +#define MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H + +#include "mozilla/layers/TextureClientOGL.h" + +class MacIOSurface; + +namespace mozilla { +namespace layers { + +class MacIOSurfaceTextureData : public TextureData +{ +public: + static MacIOSurfaceTextureData* Create(MacIOSurface* aSurface, + gfx::BackendType aBackend); + + static MacIOSurfaceTextureData* + Create(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + gfx::BackendType aBackend); + + ~MacIOSurfaceTextureData(); + + virtual void FillInfo(TextureData::Info& aInfo) const override; + + virtual bool Lock(OpenMode) override; + + virtual void Unlock() override; + + virtual already_AddRefed BorrowDrawTarget() override; + + virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override; + + virtual void Deallocate(LayersIPCChannel*) override; + + virtual void Forget(LayersIPCChannel*) override; + + virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override; + + // For debugging purposes only. + already_AddRefed GetAsSurface(); + +protected: + MacIOSurfaceTextureData(MacIOSurface* aSurface, + gfx::BackendType aBackend); + + RefPtr mSurface; + gfx::BackendType mBackend; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp new file mode 100644 index 0000000000..9736618f7e --- /dev/null +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MacIOSurfaceTextureHostOGL.h" +#include "mozilla/gfx/MacIOSurface.h" +#include "GLContextCGL.h" + +namespace mozilla { +namespace layers { + +MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags, + const SurfaceDescriptorMacIOSurface& aDescriptor) + : TextureHost(aFlags) +{ + MOZ_COUNT_CTOR(MacIOSurfaceTextureHostOGL); + mSurface = MacIOSurface::LookupSurface(aDescriptor.surfaceId(), + aDescriptor.scaleFactor(), + !aDescriptor.isOpaque()); +} + +MacIOSurfaceTextureHostOGL::~MacIOSurfaceTextureHostOGL() +{ + MOZ_COUNT_DTOR(MacIOSurfaceTextureHostOGL); +} + +GLTextureSource* +MacIOSurfaceTextureHostOGL::CreateTextureSourceForPlane(size_t aPlane) +{ + MOZ_ASSERT(mSurface); + + GLuint textureHandle; + gl::GLContext* gl = mCompositor->gl(); + gl->fGenTextures(1, &textureHandle); + gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textureHandle); + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + + mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext(), aPlane); + + return new GLTextureSource(mCompositor, textureHandle, LOCAL_GL_TEXTURE_RECTANGLE_ARB, + gfx::IntSize(mSurface->GetDevicePixelWidth(aPlane), + mSurface->GetDevicePixelHeight(aPlane)), + // XXX: This isn't really correct (but isn't used), we should be using the + // format of the individual plane, not of the whole buffer. + mSurface->GetFormat()); +} + +bool +MacIOSurfaceTextureHostOGL::Lock() +{ + if (!gl() || !gl()->MakeCurrent() || !mSurface) { + return false; + } + + if (!mTextureSource) { + mTextureSource = CreateTextureSourceForPlane(0); + + RefPtr prev = mTextureSource; + for (size_t i = 1; i < mSurface->GetPlaneCount(); i++) { + RefPtr next = CreateTextureSourceForPlane(i); + prev->SetNextSibling(next); + prev = next; + } + } + return true; +} + +void +MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor) +{ + CompositorOGL* glCompositor = AssertGLCompositor(aCompositor); + if (!glCompositor) { + mTextureSource = nullptr; + mCompositor = nullptr; + return; + } + + if (mCompositor != glCompositor) { + // Cannot share GL texture identifiers across compositors. + mTextureSource = nullptr; + } + mCompositor = glCompositor; +} + +gfx::SurfaceFormat +MacIOSurfaceTextureHostOGL::GetFormat() const { + if (!mSurface) { + return gfx::SurfaceFormat::UNKNOWN; + } + return mSurface->GetFormat(); +} + +gfx::SurfaceFormat +MacIOSurfaceTextureHostOGL::GetReadFormat() const { + if (!mSurface) { + return gfx::SurfaceFormat::UNKNOWN; + } + return mSurface->GetReadFormat(); +} + +gfx::IntSize +MacIOSurfaceTextureHostOGL::GetSize() const { + if (!mSurface) { + return gfx::IntSize(); + } + return gfx::IntSize(mSurface->GetDevicePixelWidth(), + mSurface->GetDevicePixelHeight()); +} + +gl::GLContext* +MacIOSurfaceTextureHostOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +MacIOSurfaceTextureSourceOGL::MacIOSurfaceTextureSourceOGL( + CompositorOGL* aCompositor, + MacIOSurface* aSurface) + : mCompositor(aCompositor) + , mSurface(aSurface) +{ + MOZ_ASSERT(aCompositor); + MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceOGL); +} + +MacIOSurfaceTextureSourceOGL::~MacIOSurfaceTextureSourceOGL() +{ + MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceOGL); +} + +gfx::IntSize +MacIOSurfaceTextureSourceOGL::GetSize() const +{ + return gfx::IntSize(mSurface->GetDevicePixelWidth(), + mSurface->GetDevicePixelHeight()); +} + +gfx::SurfaceFormat +MacIOSurfaceTextureSourceOGL::GetFormat() const +{ + return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 + : gfx::SurfaceFormat::R8G8B8X8; +} + +void +MacIOSurfaceTextureSourceOGL::BindTexture(GLenum aTextureUnit, + gfx::SamplingFilter aSamplingFilter) +{ + gl::GLContext* gl = this->gl(); + if (!gl || !gl->MakeCurrent()) { + NS_WARNING("Trying to bind a texture without a working GLContext"); + return; + } + GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit); + + gl->fActiveTexture(aTextureUnit); + gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, tex); + mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext()); + ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, LOCAL_GL_TEXTURE_RECTANGLE_ARB); +} + +void +MacIOSurfaceTextureSourceOGL::SetCompositor(Compositor* aCompositor) +{ + mCompositor = AssertGLCompositor(aCompositor); + if (mCompositor && mNextSibling) { + mNextSibling->SetCompositor(aCompositor); + } +} + +gl::GLContext* +MacIOSurfaceTextureSourceOGL::gl() const +{ + return mCompositor ? mCompositor->gl() : nullptr; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h new file mode 100644 index 0000000000..55e2f5019a --- /dev/null +++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H +#define MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H + +#include "mozilla/layers/CompositorOGL.h" +#include "mozilla/layers/TextureHostOGL.h" + +class MacIOSurface; + +namespace mozilla { +namespace layers { + +/** + * A texture source meant for use with MacIOSurfaceTextureHostOGL. + * + * It does not own any GL texture, and attaches its shared handle to one of + * the compositor's temporary textures when binding. + */ +class MacIOSurfaceTextureSourceOGL : public TextureSource + , public TextureSourceOGL +{ +public: + MacIOSurfaceTextureSourceOGL(CompositorOGL* aCompositor, + MacIOSurface* aSurface); + virtual ~MacIOSurfaceTextureSourceOGL(); + + virtual const char* Name() const override { return "MacIOSurfaceTextureSourceOGL"; } + + virtual TextureSourceOGL* AsSourceOGL() override { return this; } + + virtual void BindTexture(GLenum activetex, + gfx::SamplingFilter aSamplingFilter) override; + + virtual bool IsValid() const override { return !!gl(); } + + virtual gfx::IntSize GetSize() const override; + + virtual gfx::SurfaceFormat GetFormat() const override; + + virtual GLenum GetTextureTarget() const override { return LOCAL_GL_TEXTURE_RECTANGLE_ARB; } + + virtual GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; } + + // MacIOSurfaceTextureSourceOGL doesn't own any gl texture + virtual void DeallocateDeviceData() override {} + + virtual void SetCompositor(Compositor* aCompositor) override; + + gl::GLContext* gl() const; + +protected: + RefPtr mCompositor; + RefPtr mSurface; +}; + +/** + * A TextureHost for shared MacIOSurface + * + * Most of the logic actually happens in MacIOSurfaceTextureSourceOGL. + */ +class MacIOSurfaceTextureHostOGL : public TextureHost +{ +public: + MacIOSurfaceTextureHostOGL(TextureFlags aFlags, + const SurfaceDescriptorMacIOSurface& aDescriptor); + virtual ~MacIOSurfaceTextureHostOGL(); + + // MacIOSurfaceTextureSourceOGL doesn't own any GL texture + virtual void DeallocateDeviceData() override {} + + virtual void SetCompositor(Compositor* aCompositor) override; + + virtual Compositor* GetCompositor() override { return mCompositor; } + + virtual bool Lock() override; + + virtual gfx::SurfaceFormat GetFormat() const override; + virtual gfx::SurfaceFormat GetReadFormat() const override; + + virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override + { + aTexture = mTextureSource; + return !!aTexture; + } + + virtual already_AddRefed GetAsSurface() override + { + return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING) + } + + gl::GLContext* gl() const; + + virtual gfx::IntSize GetSize() const override; + +#ifdef MOZ_LAYERS_HAVE_LOG + virtual const char* Name() override { return "MacIOSurfaceTextureHostOGL"; } +#endif + +protected: + GLTextureSource* CreateTextureSourceForPlane(size_t aPlane); + + RefPtr mCompositor; + RefPtr mTextureSource; + RefPtr mSurface; +}; + +} // namespace layers +} // namespace mozilla + +#endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H diff --git a/gfx/skia/generate_mozbuild.py b/gfx/skia/generate_mozbuild.py index 22801ea9a8..a15fd40861 100755 --- a/gfx/skia/generate_mozbuild.py +++ b/gfx/skia/generate_mozbuild.py @@ -65,6 +65,7 @@ LOCAL_INCLUDES += [ ] if CONFIG['MOZ_WIDGET_TOOLKIT'] in { + 'cocoa', 'gtk2', 'gtk3', 'uikit', @@ -443,7 +444,7 @@ def write_mozbuild(sources): f.write("if CONFIG['MOZ_ENABLE_SKIA_GPU']:\n") write_sources(f, sources['gpu'], 4) - f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'uikit'}:\n") + f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}:\n") write_sources(f, sources['mac'], 4) f.write("if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:\n") diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build index 1d9d342f41..75a66dd28e 100644 --- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -516,7 +516,7 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']: 'skia/src/gpu/GrResourceCache.cpp', 'skia/src/image/SkImage_Gpu.cpp', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'uikit'}: +if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}: SOURCES += [ 'skia/src/ports/SkDebug_stdio.cpp', 'skia/src/ports/SkOSFile_posix.cpp', @@ -663,6 +663,7 @@ LOCAL_INCLUDES += [ ] if CONFIG['MOZ_WIDGET_TOOLKIT'] in { + 'cocoa', 'gtk2', 'gtk3', 'uikit', diff --git a/image/decoders/icon/mac/moz.build b/image/decoders/icon/mac/moz.build new file mode 100644 index 0000000000..f36d6ca53d --- /dev/null +++ b/image/decoders/icon/mac/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'nsIconChannelCocoa.mm', +] + +FINAL_LIBRARY = 'xul' diff --git a/image/decoders/icon/mac/nsIconChannel.h b/image/decoders/icon/mac/nsIconChannel.h new file mode 100644 index 0000000000..9fef171193 --- /dev/null +++ b/image/decoders/icon/mac/nsIconChannel.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_image_encoders_icon_mac_nsIconChannel_h +#define mozilla_image_encoders_icon_mac_nsIconChannel_h + +#include "mozilla/Attributes.h" + +#include "nsCOMPtr.h" +#include "nsXPIDLString.h" +#include "nsIChannel.h" +#include "nsILoadGroup.h" +#include "nsILoadInfo.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIInputStreamPump.h" +#include "nsIStreamListener.h" +#include "nsIURI.h" + +class nsIFile; + +class nsIconChannel final : public nsIChannel, public nsIStreamListener +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIREQUEST + NS_DECL_NSICHANNEL + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + + nsIconChannel(); + + nsresult Init(nsIURI* uri); + +protected: + virtual ~nsIconChannel(); + + nsCOMPtr mUrl; + nsCOMPtr mOriginalURI; + nsCOMPtr mLoadGroup; + nsCOMPtr mCallbacks; + nsCOMPtr mOwner; + nsCOMPtr mLoadInfo; + + nsCOMPtr mPump; + nsCOMPtr mListener; + + nsresult MakeInputStream(nsIInputStream** _retval, bool nonBlocking); + + nsresult ExtractIconInfoFromUrl(nsIFile** aLocalFile, + uint32_t* aDesiredImageSize, + nsACString& aContentType, + nsACString& aFileExtension); +}; + +#endif // mozilla_image_encoders_icon_mac_nsIconChannel_h diff --git a/image/decoders/icon/mac/nsIconChannelCocoa.mm b/image/decoders/icon/mac/nsIconChannelCocoa.mm new file mode 100644 index 0000000000..9c2686cdd2 --- /dev/null +++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm @@ -0,0 +1,565 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsContentUtils.h" +#include "nsIconChannel.h" +#include "mozilla/EndianUtils.h" +#include "nsIIconURI.h" +#include "nsIServiceManager.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsXPIDLString.h" +#include "nsMimeTypes.h" +#include "nsMemory.h" +#include "nsIStringStream.h" +#include "nsIURL.h" +#include "nsNetCID.h" +#include "nsIPipe.h" +#include "nsIOutputStream.h" +#include "nsIMIMEService.h" +#include "nsCExternalHandlerService.h" +#include "nsILocalFileMac.h" +#include "nsIFileURL.h" +#include "nsTArray.h" +#include "nsObjCExceptions.h" +#include "nsProxyRelease.h" +#include "nsContentSecurityManager.h" + +#include + +// nsIconChannel methods +nsIconChannel::nsIconChannel() +{ +} + +nsIconChannel::~nsIconChannel() +{ + if (mLoadInfo) { + NS_ReleaseOnMainThread(mLoadInfo.forget()); + } +} + +NS_IMPL_ISUPPORTS(nsIconChannel, + nsIChannel, + nsIRequest, + nsIRequestObserver, + nsIStreamListener) + +nsresult +nsIconChannel::Init(nsIURI* uri) +{ + NS_ASSERTION(uri, "no uri"); + mUrl = uri; + mOriginalURI = uri; + nsresult rv; + mPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsIRequest methods: + +NS_IMETHODIMP +nsIconChannel::GetName(nsACString& result) +{ + return mUrl->GetSpec(result); +} + +NS_IMETHODIMP +nsIconChannel::IsPending(bool* result) +{ + return mPump->IsPending(result); +} + +NS_IMETHODIMP +nsIconChannel::GetStatus(nsresult* status) +{ + return mPump->GetStatus(status); +} + +NS_IMETHODIMP +nsIconChannel::Cancel(nsresult status) +{ + return mPump->Cancel(status); +} + +NS_IMETHODIMP +nsIconChannel::Suspend(void) +{ + return mPump->Suspend(); +} + +NS_IMETHODIMP +nsIconChannel::Resume(void) +{ + return mPump->Resume(); +} + +// nsIRequestObserver methods +NS_IMETHODIMP +nsIconChannel::OnStartRequest(nsIRequest* aRequest, + nsISupports* aContext) +{ + if (mListener) { + return mListener->OnStartRequest(this, aContext); + } + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::OnStopRequest(nsIRequest* aRequest, + nsISupports* aContext, + nsresult aStatus) +{ + if (mListener) { + mListener->OnStopRequest(this, aContext, aStatus); + mListener = nullptr; + } + + // Remove from load group + if (mLoadGroup) { + mLoadGroup->RemoveRequest(this, nullptr, aStatus); + } + + return NS_OK; +} + +// nsIStreamListener methods +NS_IMETHODIMP +nsIconChannel::OnDataAvailable(nsIRequest* aRequest, + nsISupports* aContext, + nsIInputStream* aStream, + uint64_t aOffset, + uint32_t aCount) +{ + if (mListener) { + return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aCount); + } + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsIChannel methods: + +NS_IMETHODIMP +nsIconChannel::GetOriginalURI(nsIURI** aURI) +{ + *aURI = mOriginalURI; + NS_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetOriginalURI(nsIURI* aURI) +{ + NS_ENSURE_ARG_POINTER(aURI); + mOriginalURI = aURI; + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::GetURI(nsIURI** aURI) +{ + *aURI = mUrl; + NS_IF_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::Open(nsIInputStream** _retval) +{ + return MakeInputStream(_retval, false); +} + +NS_IMETHODIMP +nsIconChannel::Open2(nsIInputStream** aStream) +{ + nsCOMPtr listener; + nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); + NS_ENSURE_SUCCESS(rv, rv); + return Open(aStream); +} + +nsresult +nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, + uint32_t* aDesiredImageSize, + nsACString& aContentType, + nsACString& aFileExtension) +{ + nsresult rv = NS_OK; + nsCOMPtr iconURI (do_QueryInterface(mUrl, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + iconURI->GetImageSize(aDesiredImageSize); + iconURI->GetContentType(aContentType); + iconURI->GetFileExtension(aFileExtension); + + nsCOMPtr url; + rv = iconURI->GetIconURL(getter_AddRefs(url)); + if (NS_FAILED(rv) || !url) return NS_OK; + + nsCOMPtr fileURL = do_QueryInterface(url, &rv); + if (NS_FAILED(rv) || !fileURL) return NS_OK; + + nsCOMPtr file; + rv = fileURL->GetFile(getter_AddRefs(file)); + if (NS_FAILED(rv) || !file) return NS_OK; + + nsCOMPtr localFileMac (do_QueryInterface(file, &rv)); + if (NS_FAILED(rv) || !localFileMac) return NS_OK; + + *aLocalFile = file; + NS_IF_ADDREF(*aLocalFile); + + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::AsyncOpen(nsIStreamListener* aListener, + nsISupports* ctxt) +{ + MOZ_ASSERT(!mLoadInfo || + mLoadInfo->GetSecurityMode() == 0 || + mLoadInfo->GetInitialSecurityCheckDone() || + (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL && + nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())), + "security flags in loadInfo but asyncOpen2() not called"); + + nsCOMPtr inStream; + nsresult rv = MakeInputStream(getter_AddRefs(inStream), true); + NS_ENSURE_SUCCESS(rv, rv); + + // Init our stream pump + rv = mPump->Init(inStream, int64_t(-1), int64_t(-1), 0, 0, false); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mPump->AsyncRead(this, ctxt); + if (NS_SUCCEEDED(rv)) { + // Store our real listener + mListener = aListener; + // Add ourself to the load group, if available + if (mLoadGroup) { + mLoadGroup->AddRequest(this, nullptr); + } + } + + return rv; +} + +NS_IMETHODIMP +nsIconChannel::AsyncOpen2(nsIStreamListener* aListener) +{ + nsCOMPtr listener = aListener; + nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); + NS_ENSURE_SUCCESS(rv, rv); + return AsyncOpen(listener, nullptr); +} + +nsresult +nsIconChannel::MakeInputStream(nsIInputStream** _retval, + bool aNonBlocking) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + nsXPIDLCString contentType; + nsAutoCString fileExt; + nsCOMPtr fileloc; // file we want an icon for + uint32_t desiredImageSize; + nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(fileloc), + &desiredImageSize, contentType, fileExt); + NS_ENSURE_SUCCESS(rv, rv); + + bool fileExists = false; + if (fileloc) { + // ensure that we DO NOT resolve aliases, very important for file views + fileloc->SetFollowLinks(false); + fileloc->Exists(&fileExists); + } + + NSImage* iconImage = nil; + + // first try to get the icon from the file if it exists + if (fileExists) { + nsCOMPtr localFileMac(do_QueryInterface(fileloc, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + CFURLRef macURL; + if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) { + iconImage = [[NSWorkspace sharedWorkspace] + iconForFile:[(NSURL*)macURL path]]; + ::CFRelease(macURL); + } + } + + // if we don't have an icon yet try to get one by extension + if (!iconImage && !fileExt.IsEmpty()) { + NSString* fileExtension = [NSString stringWithUTF8String:fileExt.get()]; + iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:fileExtension]; + } + + // If we still don't have an icon, get the generic document icon. + if (!iconImage) { + iconImage = [[NSWorkspace sharedWorkspace] + iconForFileType:NSFileTypeUnknown]; + } + + if (!iconImage) { + return NS_ERROR_FAILURE; + } + + // we have an icon now, size it + NSRect desiredSizeRect = NSMakeRect(0, 0, desiredImageSize, desiredImageSize); + [iconImage setSize:desiredSizeRect.size]; + + [iconImage lockFocus]; + NSBitmapImageRep* bitmapRep = [[[NSBitmapImageRep alloc] + initWithFocusedViewRect:desiredSizeRect] + autorelease]; + [iconImage unlockFocus]; + + // we expect the following things to be true about our bitmapRep + NS_ENSURE_TRUE(![bitmapRep isPlanar] && + // Not necessarily: on a HiDPI-capable system, we'll get + // a 2x bitmap + // (unsigned int)[bitmapRep bytesPerPlane] == + // desiredImageSize * desiredImageSize * 4 && + [bitmapRep bitsPerPixel] == 32 && + [bitmapRep samplesPerPixel] == 4 && + [bitmapRep hasAlpha] == YES, + NS_ERROR_UNEXPECTED); + + // check what size we actually got, and ensure it isn't too big to return + uint32_t actualImageSize = [bitmapRep bytesPerRow] / 4; + NS_ENSURE_TRUE(actualImageSize < 256, NS_ERROR_UNEXPECTED); + + // now we can validate the amount of data + NS_ENSURE_TRUE((unsigned int)[bitmapRep bytesPerPlane] == + actualImageSize * actualImageSize * 4, + NS_ERROR_UNEXPECTED); + + // rgba, pre-multiplied data + uint8_t* bitmapRepData = (uint8_t*)[bitmapRep bitmapData]; + + // create our buffer + int32_t bufferCapacity = 2 + [bitmapRep bytesPerPlane]; + AutoTArray iconBuffer; // initial size is for + // 16x16 + iconBuffer.SetLength(bufferCapacity); + + uint8_t* iconBufferPtr = iconBuffer.Elements(); + + // write header data into buffer + *iconBufferPtr++ = actualImageSize; + *iconBufferPtr++ = actualImageSize; + + uint32_t dataCount = [bitmapRep bytesPerPlane]; + uint32_t index = 0; + while (index < dataCount) { + // get data from the bitmap + uint8_t r = bitmapRepData[index++]; + uint8_t g = bitmapRepData[index++]; + uint8_t b = bitmapRepData[index++]; + uint8_t a = bitmapRepData[index++]; + + // write data out to our buffer + // non-cairo uses native image format, but the A channel is ignored. + // cairo uses ARGB (highest to lowest bits) +#if MOZ_LITTLE_ENDIAN + *iconBufferPtr++ = b; + *iconBufferPtr++ = g; + *iconBufferPtr++ = r; + *iconBufferPtr++ = a; +#else + *iconBufferPtr++ = a; + *iconBufferPtr++ = r; + *iconBufferPtr++ = g; + *iconBufferPtr++ = b; +#endif + } + + NS_ASSERTION(iconBufferPtr == iconBuffer.Elements() + bufferCapacity, + "buffer size miscalculation"); + + // Now, create a pipe and stuff our data into it + nsCOMPtr inStream; + nsCOMPtr outStream; + rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), + bufferCapacity, bufferCapacity, aNonBlocking); + + if (NS_SUCCEEDED(rv)) { + uint32_t written; + rv = outStream->Write((char*)iconBuffer.Elements(), bufferCapacity, + &written); + if (NS_SUCCEEDED(rv)) { + NS_IF_ADDREF(*_retval = inStream); + } + } + + // Drop notification callbacks to prevent cycles. + mCallbacks = nullptr; + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +nsIconChannel::GetLoadFlags(uint32_t* aLoadAttributes) +{ + return mPump->GetLoadFlags(aLoadAttributes); +} + +NS_IMETHODIMP +nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) +{ + return mPump->SetLoadFlags(aLoadAttributes); +} + +NS_IMETHODIMP +nsIconChannel::GetContentType(nsACString& aContentType) +{ + aContentType.AssignLiteral(IMAGE_ICON_MS); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetContentType(const nsACString& aContentType) +{ + //It doesn't make sense to set the content-type on this type + // of channel... + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsIconChannel::GetContentCharset(nsACString& aContentCharset) +{ + aContentCharset.AssignLiteral(IMAGE_ICON_MS); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetContentCharset(const nsACString& aContentCharset) +{ + //It doesn't make sense to set the content-type on this type + // of channel... + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsIconChannel::GetContentDisposition(uint32_t* aContentDisposition) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsIconChannel:: + GetContentDispositionFilename(nsAString& aContentDispositionFilename) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsIconChannel:: + SetContentDispositionFilename(const nsAString& aContentDispositionFilename) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsIconChannel:: + GetContentDispositionHeader(nsACString& aContentDispositionHeader) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsIconChannel::GetContentLength(int64_t* aContentLength) +{ + *aContentLength = 0; + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsIconChannel::SetContentLength(int64_t aContentLength) +{ + NS_NOTREACHED("nsIconChannel::SetContentLength"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsIconChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) +{ + *aLoadGroup = mLoadGroup; + NS_IF_ADDREF(*aLoadGroup); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) +{ + mLoadGroup = aLoadGroup; + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::GetOwner(nsISupports** aOwner) +{ + *aOwner = mOwner.get(); + NS_IF_ADDREF(*aOwner); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetOwner(nsISupports* aOwner) +{ + mOwner = aOwner; + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) +{ + NS_IF_ADDREF(*aLoadInfo = mLoadInfo); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) +{ + mLoadInfo = aLoadInfo; + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel:: + GetNotificationCallbacks(nsIInterfaceRequestor** aNotificationCallbacks) +{ + *aNotificationCallbacks = mCallbacks.get(); + NS_IF_ADDREF(*aNotificationCallbacks); + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel:: + SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) +{ + mCallbacks = aNotificationCallbacks; + return NS_OK; +} + +NS_IMETHODIMP +nsIconChannel::GetSecurityInfo(nsISupports** aSecurityInfo) +{ + *aSecurityInfo = nullptr; + return NS_OK; +} + diff --git a/image/decoders/icon/moz.build b/image/decoders/icon/moz.build index 56465dd274..5a173d3169 100644 --- a/image/decoders/icon/moz.build +++ b/image/decoders/icon/moz.build @@ -21,5 +21,8 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: if CONFIG['OS_ARCH'] == 'WINNT': platform = 'win' +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + platform = 'mac' + if platform: LOCAL_INCLUDES += [platform] diff --git a/image/decoders/moz.build b/image/decoders/moz.build index 5a07bf765f..907b81bda8 100644 --- a/image/decoders/moz.build +++ b/image/decoders/moz.build @@ -13,6 +13,9 @@ if 'gtk' in toolkit: if CONFIG['OS_ARCH'] == 'WINNT': DIRS += ['icon/win', 'icon'] +if toolkit == 'cocoa': + DIRS += ['icon/mac', 'icon'] + UNIFIED_SOURCES += [ 'EXIF.cpp', 'iccjpeg.c', diff --git a/intl/locale/mac/moz.build b/intl/locale/mac/moz.build new file mode 100644 index 0000000000..422fd3e3cd --- /dev/null +++ b/intl/locale/mac/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'nsCollationMacUC.cpp', + 'nsDateTimeFormatMac.cpp', + 'nsMacCharset.cpp', +] + +FINAL_LIBRARY = 'xul' +LOCAL_INCLUDES += [ + '..', +] diff --git a/intl/locale/mac/nsCollationMacUC.cpp b/intl/locale/mac/nsCollationMacUC.cpp new file mode 100644 index 0000000000..d230f4d771 --- /dev/null +++ b/intl/locale/mac/nsCollationMacUC.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCollationMacUC.h" +#include "nsILocaleService.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsIServiceManager.h" +#include "prmem.h" +#include "nsString.h" + +NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation) + +nsCollationMacUC::nsCollationMacUC() + : mInit(false) + , mHasCollator(false) + , mLocaleICU(nullptr) + , mLastStrength(-1) + , mCollatorICU(nullptr) +{ } + +nsCollationMacUC::~nsCollationMacUC() +{ +#ifdef DEBUG + nsresult res = +#endif + CleanUpCollator(); + NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed"); + if (mLocaleICU) { + free(mLocaleICU); + mLocaleICU = nullptr; + } +} + +nsresult nsCollationMacUC::ConvertStrength(const int32_t aNSStrength, + UCollationStrength* aICUStrength, + UColAttributeValue* aCaseLevelOut) +{ + NS_ENSURE_ARG_POINTER(aICUStrength); + NS_ENSURE_TRUE((aNSStrength < 4), NS_ERROR_FAILURE); + + UCollationStrength strength = UCOL_DEFAULT; + UColAttributeValue caseLevel = UCOL_OFF; + switch (aNSStrength) { + case kCollationCaseInSensitive: + strength = UCOL_PRIMARY; + break; + case kCollationCaseInsensitiveAscii: + strength = UCOL_SECONDARY; + break; + case kCollationAccentInsenstive: + caseLevel = UCOL_ON; + strength = UCOL_PRIMARY; + break; + case kCollationCaseSensitive: + strength = UCOL_TERTIARY; + break; + default: + NS_WARNING("Bad aNSStrength passed to ConvertStrength."); + return NS_ERROR_FAILURE; + } + + *aICUStrength = strength; + *aCaseLevelOut = caseLevel; + + return NS_OK; +} + +nsresult nsCollationMacUC::ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale) +{ + NS_ENSURE_ARG_POINTER(aNSLocale); + NS_ENSURE_ARG_POINTER(aICULocale); + + nsAutoString localeString; + nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString); + NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(), + NS_ERROR_FAILURE); + NS_LossyConvertUTF16toASCII tmp(localeString); + tmp.ReplaceChar('-', '_'); + char* locale = (char*)malloc(tmp.Length() + 1); + if (!locale) { + return NS_ERROR_OUT_OF_MEMORY; + } + strcpy(locale, tmp.get()); + + *aICULocale = locale; + + return NS_OK; +} + +nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength) +{ + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); + if (mHasCollator && (mLastStrength == newStrength)) + return NS_OK; + + nsresult res; + res = CleanUpCollator(); + NS_ENSURE_SUCCESS(res, res); + + NS_ENSURE_TRUE(mLocaleICU, NS_ERROR_NOT_INITIALIZED); + + UErrorCode status; + status = U_ZERO_ERROR; + mCollatorICU = ucol_open(mLocaleICU, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + + UCollationStrength strength; + UColAttributeValue caseLevel; + res = ConvertStrength(newStrength, &strength, &caseLevel); + NS_ENSURE_SUCCESS(res, res); + + status = U_ZERO_ERROR; + ucol_setAttribute(mCollatorICU, UCOL_STRENGTH, strength, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + ucol_setAttribute(mCollatorICU, UCOL_CASE_LEVEL, caseLevel, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + ucol_setAttribute(mCollatorICU, UCOL_ALTERNATE_HANDLING, UCOL_DEFAULT, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + ucol_setAttribute(mCollatorICU, UCOL_NUMERIC_COLLATION, UCOL_OFF, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + ucol_setAttribute(mCollatorICU, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + ucol_setAttribute(mCollatorICU, UCOL_CASE_FIRST, UCOL_DEFAULT, &status); + NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE); + + mHasCollator = true; + + mLastStrength = newStrength; + return NS_OK; +} + +nsresult nsCollationMacUC::CleanUpCollator(void) +{ + if (mHasCollator) { + ucol_close(mCollatorICU); + mHasCollator = false; + } + + return NS_OK; +} + +NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale) +{ + NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED); + nsCOMPtr appLocale; + + nsresult rv; + if (!locale) { + nsCOMPtr localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); + NS_ENSURE_SUCCESS(rv, rv); + locale = appLocale; + } + + rv = ConvertLocaleICU(locale, &mLocaleICU); + NS_ENSURE_SUCCESS(rv, rv); + + mInit = true; + return NS_OK; +} + +NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsAString& stringIn, + uint8_t** key, uint32_t* outLen) +{ + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_ARG_POINTER(key); + NS_ENSURE_ARG_POINTER(outLen); + + nsresult res = EnsureCollator(strength); + NS_ENSURE_SUCCESS(res, res); + + uint32_t stringInLen = stringIn.Length(); + + const UChar* str = (const UChar*)stringIn.BeginReading(); + + int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0); + NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE); + + // Since key is freed elsewhere with PR_Free, allocate with PR_Malloc. + uint8_t* newKey = (uint8_t*)PR_Malloc(keyLength + 1); + if (!newKey) { + return NS_ERROR_OUT_OF_MEMORY; + } + + keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, newKey, keyLength + 1); + NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE); + + *key = newKey; + *outLen = keyLength; + + return NS_OK; +} + +NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1, + const nsAString& string2, int32_t* result) +{ + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_ARG_POINTER(result); + *result = 0; + + nsresult rv = EnsureCollator(strength); + NS_ENSURE_SUCCESS(rv, rv); + + UCollationResult uresult; + uresult = ucol_strcoll(mCollatorICU, + (const UChar*)string1.BeginReading(), + string1.Length(), + (const UChar*)string2.BeginReading(), + string2.Length()); + int32_t res; + switch (uresult) { + case UCOL_LESS: + res = -1; + break; + case UCOL_EQUAL: + res = 0; + break; + case UCOL_GREATER: + res = 1; + break; + default: + MOZ_CRASH("ucol_strcoll returned bad UCollationResult"); + } + *result = res; + return NS_OK; +} + +NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t len1, + const uint8_t* key2, uint32_t len2, + int32_t* result) +{ + NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_ARG_POINTER(key1); + NS_ENSURE_ARG_POINTER(key2); + NS_ENSURE_ARG_POINTER(result); + *result = 0; + + int32_t tmpResult = strcmp((const char*)key1, (const char*)key2); + int32_t res; + if (tmpResult < 0) { + res = -1; + } else if (tmpResult > 0) { + res = 1; + } else { + res = 0; + } + *result = res; + return NS_OK; +} diff --git a/intl/locale/mac/nsCollationMacUC.h b/intl/locale/mac/nsCollationMacUC.h new file mode 100644 index 0000000000..46bb0145de --- /dev/null +++ b/intl/locale/mac/nsCollationMacUC.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCollationMacUC_h_ +#define nsCollationMacUC_h_ + +#include "nsICollation.h" +#include "nsCollation.h" +#include "mozilla/Attributes.h" + +#include "unicode/ucol.h" + +class nsCollationMacUC final : public nsICollation { + +public: + nsCollationMacUC(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsICollation interface + NS_DECL_NSICOLLATION + +protected: + ~nsCollationMacUC(); + + nsresult ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale); + nsresult ConvertStrength(const int32_t aStrength, + UCollationStrength* aStrengthOut, + UColAttributeValue* aCaseLevelOut); + nsresult EnsureCollator(const int32_t newStrength); + nsresult CleanUpCollator(void); + +private: + bool mInit; + bool mHasCollator; + char* mLocaleICU; + int32_t mLastStrength; + UCollator* mCollatorICU; +}; + +#endif /* nsCollationMacUC_h_ */ diff --git a/intl/locale/mac/nsDateTimeFormatMac.cpp b/intl/locale/mac/nsDateTimeFormatMac.cpp new file mode 100644 index 0000000000..6ee73292d7 --- /dev/null +++ b/intl/locale/mac/nsDateTimeFormatMac.cpp @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "nsIServiceManager.h" +#include "nsDateTimeFormatMac.h" +#include +#include "nsIComponentManager.h" +#include "nsILocaleService.h" +#include "nsCRT.h" +#include "plstr.h" +#include "nsUnicharUtils.h" +#include "nsTArray.h" + + +NS_IMPL_ISUPPORTS(nsDateTimeFormatMac, nsIDateTimeFormat) + +nsresult nsDateTimeFormatMac::Initialize(nsILocale* locale) +{ + nsAutoString localeStr; + nsAutoString category(NS_LITERAL_STRING("NSILOCALE_TIME")); + nsresult res; + + // use cached info if match with stored locale + if (nullptr == locale) { + if (!mLocale.IsEmpty() && + mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) { + return NS_OK; + } + } + else { + res = locale->GetCategory(category, localeStr); + if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { + if (!mLocale.IsEmpty() && + mLocale.Equals(localeStr, + nsCaseInsensitiveStringComparator())) { + return NS_OK; + } + } + } + + // get application locale + nsCOMPtr localeService = + do_GetService(NS_LOCALESERVICE_CONTRACTID, &res); + if (NS_SUCCEEDED(res)) { + nsCOMPtr appLocale; + res = localeService->GetApplicationLocale(getter_AddRefs(appLocale)); + if (NS_SUCCEEDED(res)) { + res = appLocale->GetCategory(category, localeStr); + if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { + mAppLocale = localeStr; // cache app locale name + } + } + } + + // use app default if no locale specified + if (nullptr == locale) { + mUseDefaultLocale = true; + } + else { + mUseDefaultLocale = false; + res = locale->GetCategory(category, localeStr); + } + + if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) { + mLocale.Assign(localeStr); // cache locale name + } + + return res; +} + +// performs a locale sensitive date formatting operation on the time_t parameter +nsresult nsDateTimeFormatMac::FormatTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const time_t timetTime, + nsAString& stringOut) +{ + struct tm tmTime; + return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime_r(&timetTime, &tmTime), stringOut); +} + +// performs a locale sensitive date formatting operation on the struct tm parameter +nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const struct tm* tmTime, + nsAString& stringOut) +{ + nsresult res = NS_OK; + + // set up locale data + (void) Initialize(locale); + + // return, nothing to format + if (dateFormatSelector == kDateFormatNone && timeFormatSelector == kTimeFormatNone) { + stringOut.Truncate(); + return NS_OK; + } + + NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly"); + NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly"); + NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly"); + NS_ASSERTION(tmTime->tm_min >= 0, "tm is not set correctly"); + NS_ASSERTION(tmTime->tm_sec >= 0, "tm is not set correctly"); + NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly"); + + // Got the locale for the formatter: + CFLocaleRef formatterLocale; + if (!locale) { + formatterLocale = CFLocaleCopyCurrent(); + } else { + CFStringRef localeStr = CFStringCreateWithCharacters(nullptr, + reinterpret_cast(mLocale.get()), + mLocale.Length()); + formatterLocale = CFLocaleCreate(nullptr, localeStr); + CFRelease(localeStr); + } + + // Get the date style for the formatter: + CFDateFormatterStyle dateStyle; + switch (dateFormatSelector) { + case kDateFormatLong: + dateStyle = kCFDateFormatterLongStyle; + break; + case kDateFormatShort: + dateStyle = kCFDateFormatterShortStyle; + break; + case kDateFormatYearMonth: + case kDateFormatWeekday: + dateStyle = kCFDateFormatterNoStyle; // formats handled below + break; + case kDateFormatNone: + dateStyle = kCFDateFormatterNoStyle; + break; + default: + NS_ERROR("Unknown nsDateFormatSelector"); + res = NS_ERROR_FAILURE; + dateStyle = kCFDateFormatterNoStyle; + } + + // Get the time style for the formatter: + CFDateFormatterStyle timeStyle; + switch (timeFormatSelector) { + case kTimeFormatSeconds: + case kTimeFormatSecondsForce24Hour: // 24 hour part fixed below + timeStyle = kCFDateFormatterMediumStyle; + break; + case kTimeFormatNoSeconds: + case kTimeFormatNoSecondsForce24Hour: // 24 hour part fixed below + timeStyle = kCFDateFormatterShortStyle; + break; + case kTimeFormatNone: + timeStyle = kCFDateFormatterNoStyle; + break; + default: + NS_ERROR("Unknown nsTimeFormatSelector"); + res = NS_ERROR_FAILURE; + timeStyle = kCFDateFormatterNoStyle; + } + + // Create the formatter and fix up its formatting as necessary: + CFDateFormatterRef formatter = + CFDateFormatterCreate(nullptr, formatterLocale, dateStyle, timeStyle); + + CFRelease(formatterLocale); + + if (dateFormatSelector == kDateFormatYearMonth || + dateFormatSelector == kDateFormatWeekday) { + CFStringRef dateFormat = + dateFormatSelector == kDateFormatYearMonth ? CFSTR("yyyy/MM ") : CFSTR("EEE "); + + CFStringRef oldFormat = CFDateFormatterGetFormat(formatter); + CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat); + CFStringInsert(newFormat, 0, dateFormat); + CFDateFormatterSetFormat(formatter, newFormat); + CFRelease(newFormat); // note we don't own oldFormat + } + + if (timeFormatSelector == kTimeFormatSecondsForce24Hour || + timeFormatSelector == kTimeFormatNoSecondsForce24Hour) { + // Replace "h" with "H", and remove "a": + CFStringRef oldFormat = CFDateFormatterGetFormat(formatter); + CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat); + CFIndex replaceCount = CFStringFindAndReplace(newFormat, + CFSTR("h"), CFSTR("H"), + CFRangeMake(0, CFStringGetLength(newFormat)), + 0); + NS_ASSERTION(replaceCount <= 2, "Unexpected number of \"h\" occurrences"); + replaceCount = CFStringFindAndReplace(newFormat, + CFSTR("a"), CFSTR(""), + CFRangeMake(0, CFStringGetLength(newFormat)), + 0); + NS_ASSERTION(replaceCount <= 1, "Unexpected number of \"a\" occurrences"); + CFDateFormatterSetFormat(formatter, newFormat); + CFRelease(newFormat); // note we don't own oldFormat + } + + // Now get the formatted date: + CFGregorianDate date; + date.second = tmTime->tm_sec; + date.minute = tmTime->tm_min; + date.hour = tmTime->tm_hour; + date.day = tmTime->tm_mday; // Mac is 1-based, tm is 1-based + date.month = tmTime->tm_mon + 1; // Mac is 1-based, tm is 0-based + date.year = tmTime->tm_year + 1900; + + CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); // tmTime is in local time + CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone); + CFRelease(timeZone); + + CFStringRef formattedDate = CFDateFormatterCreateStringWithAbsoluteTime(nullptr, + formatter, + absTime); + + CFIndex stringLen = CFStringGetLength(formattedDate); + + AutoTArray stringBuffer; + stringBuffer.SetLength(stringLen + 1); + CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements()); + stringOut.Assign(reinterpret_cast(stringBuffer.Elements()), stringLen); + + CFRelease(formattedDate); + CFRelease(formatter); + + return res; +} + +// performs a locale sensitive date formatting operation on the PRTime parameter +nsresult nsDateTimeFormatMac::FormatPRTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const PRTime prTime, + nsAString& stringOut) +{ + PRExplodedTime explodedTime; + PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime); + + return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut); +} + +// performs a locale sensitive date formatting operation on the PRExplodedTime parameter +nsresult nsDateTimeFormatMac::FormatPRExplodedTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const PRExplodedTime* explodedTime, + nsAString& stringOut) +{ + struct tm tmTime; + memset( &tmTime, 0, sizeof(tmTime) ); + + tmTime.tm_yday = explodedTime->tm_yday; + tmTime.tm_wday = explodedTime->tm_wday; + tmTime.tm_year = explodedTime->tm_year; + tmTime.tm_year -= 1900; + tmTime.tm_mon = explodedTime->tm_month; + tmTime.tm_mday = explodedTime->tm_mday; + tmTime.tm_hour = explodedTime->tm_hour; + tmTime.tm_min = explodedTime->tm_min; + tmTime.tm_sec = explodedTime->tm_sec; + + return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut); +} + diff --git a/intl/locale/mac/nsDateTimeFormatMac.h b/intl/locale/mac/nsDateTimeFormatMac.h new file mode 100644 index 0000000000..dfdf703780 --- /dev/null +++ b/intl/locale/mac/nsDateTimeFormatMac.h @@ -0,0 +1,61 @@ + +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef nsDateTimeFormatMac_h__ +#define nsDateTimeFormatMac_h__ + + +#include "nsCOMPtr.h" +#include "nsIDateTimeFormat.h" + + +class nsDateTimeFormatMac : public nsIDateTimeFormat { + +public: + NS_DECL_THREADSAFE_ISUPPORTS + + // performs a locale sensitive date formatting operation on the time_t parameter + NS_IMETHOD FormatTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const time_t timetTime, + nsAString& stringOut) override; + + // performs a locale sensitive date formatting operation on the struct tm parameter + NS_IMETHOD FormatTMTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const struct tm* tmTime, + nsAString& stringOut) override; + // performs a locale sensitive date formatting operation on the PRTime parameter + NS_IMETHOD FormatPRTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const PRTime prTime, + nsAString& stringOut) override; + + // performs a locale sensitive date formatting operation on the PRExplodedTime parameter + NS_IMETHOD FormatPRExplodedTime(nsILocale* locale, + const nsDateFormatSelector dateFormatSelector, + const nsTimeFormatSelector timeFormatSelector, + const PRExplodedTime* explodedTime, + nsAString& stringOut) override; + + nsDateTimeFormatMac() {} + +protected: + virtual ~nsDateTimeFormatMac() {} + +private: + // init this interface to a specified locale + NS_IMETHOD Initialize(nsILocale* locale); + + nsString mLocale; + nsString mAppLocale; + bool mUseDefaultLocale; +}; + +#endif /* nsDateTimeFormatMac_h__ */ diff --git a/intl/locale/mac/nsMacCharset.cpp b/intl/locale/mac/nsMacCharset.cpp new file mode 100644 index 0000000000..956560fba8 --- /dev/null +++ b/intl/locale/mac/nsMacCharset.cpp @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "nsIPlatformCharset.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsReadableUtils.h" +#include "nsPlatformCharset.h" +#include "nsEncoderDecoderUtils.h" + +NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset) + +nsPlatformCharset::nsPlatformCharset() +{ +} +nsPlatformCharset::~nsPlatformCharset() +{ +} + +NS_IMETHODIMP +nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult) +{ + oResult.AssignLiteral("UTF-8"); + return NS_OK; +} + +NS_IMETHODIMP +nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult) +{ + oResult.AssignLiteral("UTF-8"); + return NS_OK; +} + +NS_IMETHODIMP +nsPlatformCharset::Init() +{ + return NS_OK; +} + +nsresult +nsPlatformCharset::MapToCharset(nsAString& inANSICodePage, nsACString& outCharset) +{ + return NS_OK; +} + +nsresult +nsPlatformCharset::InitGetCharset(nsACString &oString) +{ + return NS_OK; +} + +nsresult +nsPlatformCharset::VerifyCharset(nsCString &aCharset) +{ + return NS_OK; +} diff --git a/intl/locale/moz.build b/intl/locale/moz.build index 4b3b3c0b88..94a30873ba 100644 --- a/intl/locale/moz.build +++ b/intl/locale/moz.build @@ -9,6 +9,8 @@ toolkit = CONFIG['MOZ_WIDGET_TOOLKIT'] if toolkit == 'windows': DIRS += ['windows'] +elif toolkit == 'cocoa': + DIRS += ['mac'] else: DIRS += ['unix'] diff --git a/intl/lwbrk/moz.build b/intl/lwbrk/moz.build index dc7c2df1a2..da701be5e5 100644 --- a/intl/lwbrk/moz.build +++ b/intl/lwbrk/moz.build @@ -32,6 +32,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': SOURCES += [ 'nsUniscribeBreaker.cpp', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + UNIFIED_SOURCES += [ + 'nsCarbonBreaker.cpp', + ] else: SOURCES += [ 'nsRuleBreaker.cpp', diff --git a/intl/lwbrk/nsCarbonBreaker.cpp b/intl/lwbrk/nsCarbonBreaker.cpp new file mode 100644 index 0000000000..1b37bc1298 --- /dev/null +++ b/intl/lwbrk/nsCarbonBreaker.cpp @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include "nsDebug.h" +#include "nscore.h" + +void +NS_GetComplexLineBreaks(const char16_t* aText, uint32_t aLength, + uint8_t* aBreakBefore) +{ + NS_ASSERTION(aText, "aText shouldn't be null"); + + memset(aBreakBefore, 0, aLength * sizeof(uint8_t)); + + CFStringRef str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast(aText), aLength, kCFAllocatorNull); + if (!str) { + return; + } + + CFStringTokenizerRef st = ::CFStringTokenizerCreate(kCFAllocatorDefault, str, + ::CFRangeMake(0, aLength), + kCFStringTokenizerUnitLineBreak, + nullptr); + if (!st) { + ::CFRelease(str); + return; + } + + CFStringTokenizerTokenType tt = ::CFStringTokenizerAdvanceToNextToken(st); + while (tt != kCFStringTokenizerTokenNone) { + CFRange r = ::CFStringTokenizerGetCurrentTokenRange(st); + if (r.location != 0) { // Ignore leading edge + aBreakBefore[r.location] = true; + } + tt = CFStringTokenizerAdvanceToNextToken(st); + } + + ::CFRelease(st); + ::CFRelease(str); +} diff --git a/js/xpconnect/shell/moz.build b/js/xpconnect/shell/moz.build index 3361b7d810..c1789fdc71 100644 --- a/js/xpconnect/shell/moz.build +++ b/js/xpconnect/shell/moz.build @@ -14,6 +14,11 @@ SOURCES += [ 'xpcshell.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'xpcshellMacUtils.mm', + ] + include('/ipc/chromium/chromium-config.mozbuild') LOCAL_INCLUDES += [ diff --git a/js/xpconnect/shell/xpcshellMacUtils.h b/js/xpconnect/shell/xpcshellMacUtils.h new file mode 100644 index 0000000000..2e6b5cb359 --- /dev/null +++ b/js/xpconnect/shell/xpcshellMacUtils.h @@ -0,0 +1,8 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Functions to setup and release the Mac memory pool +void InitAutoreleasePool(); +void FinishAutoreleasePool(); diff --git a/js/xpconnect/shell/xpcshellMacUtils.mm b/js/xpconnect/shell/xpcshellMacUtils.mm new file mode 100644 index 0000000000..61d6a9ea9a --- /dev/null +++ b/js/xpconnect/shell/xpcshellMacUtils.mm @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +static NSAutoreleasePool *pool = NULL; + +void InitAutoreleasePool() +{ + pool = [[NSAutoreleasePool alloc] init]; +} + +void FinishAutoreleasePool() +{ + [pool release]; +} diff --git a/layout/build/moz.build b/layout/build/moz.build index 3e76edc491..d7996af8d9 100644 --- a/layout/build/moz.build +++ b/layout/build/moz.build @@ -63,6 +63,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += [ '/dom/system/windows', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/dom/system/mac', + ] elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: LOCAL_INCLUDES += [ '/widget/gtk', diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index 15840f38e5..90320cba30 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -347,6 +347,9 @@ include text-svgglyphs/reftest.list # text-transform/ include text-transform/reftest.list +# theme (osx) +include ../../toolkit/themes/osx/reftests/reftest.list + include ../../toolkit/content/tests/reftests/reftest.list # -moz-transform/ diff --git a/mailnews/base/ispdata/moz.build b/mailnews/base/ispdata/moz.build index 363c2ba0c2..7de5dc2e32 100644 --- a/mailnews/base/ispdata/moz.build +++ b/mailnews/base/ispdata/moz.build @@ -2,4 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -# Stub. This was configuring special snowflake OSX stuff. \ No newline at end of file +# Disable movemail for Thunderbird on OSX +if CONFIG['MOZ_MOVEMAIL'] and not (CONFIG['MOZ_THUNDERBIRD'] and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa'): + FINAL_TARGET_FILES.isp += ['movemail.rdf'] diff --git a/mailnews/base/src/moz.build b/mailnews/base/src/moz.build index 65853daf96..91bf235c34 100644 --- a/mailnews/base/src/moz.build +++ b/mailnews/base/src/moz.build @@ -61,6 +61,8 @@ if CONFIG['OS_ARCH'] == 'WINNT': if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'qt'): SOURCES += ['nsMessengerUnixIntegration.cpp'] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += ['nsMessengerOSXIntegration.mm'] EXTRA_COMPONENTS += [ 'folderLookupService.js', diff --git a/mailnews/base/src/nsMessengerOSXIntegration.h b/mailnews/base/src/nsMessengerOSXIntegration.h new file mode 100644 index 0000000000..91f42f2a2a --- /dev/null +++ b/mailnews/base/src/nsMessengerOSXIntegration.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __nsMessengerOSXIntegration_h +#define __nsMessengerOSXIntegration_h + +#include "nsIMessengerOSIntegration.h" +#include "nsIFolderListener.h" +#include "nsIAtom.h" +#include "nsITimer.h" +#include "nsCOMPtr.h" +#include "nsStringGlue.h" +#include "nsIObserver.h" +#include "nsIAlertsService.h" +#include "mozINewMailListener.h" + +#define NS_MESSENGEROSXINTEGRATION_CID \ + {0xaa83266, 0x4225, 0x4c4b, \ + {0x93, 0xf8, 0x94, 0xb1, 0x82, 0x58, 0x6f, 0x93}} + +class nsIStringBundle; + +class nsMessengerOSXIntegration : public nsIMessengerOSIntegration, + public nsIFolderListener, + public nsIObserver, + public mozINewMailListener +{ +public: + nsMessengerOSXIntegration(); + virtual nsresult Init(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIMESSENGEROSINTEGRATION + NS_DECL_NSIFOLDERLISTENER + NS_DECL_NSIOBSERVER + NS_DECL_MOZINEWMAILLISTENER + +private: + virtual ~nsMessengerOSXIntegration(); + + nsCOMPtr mBiffStateAtom; + nsCOMPtr mNewMailReceivedAtom; + nsresult ShowAlertMessage(const nsAString& aAlertTitle, const nsAString& aAlertText, const nsACString& aFolderURI); + nsresult OnAlertFinished(); + nsresult OnAlertClicked(const char16_t * aAlertCookie); +#ifdef MOZ_SUITE + nsresult OnAlertClickedSimple(); +#endif + nsresult GetStringBundle(nsIStringBundle **aBundle); + void FillToolTipInfo(nsIMsgFolder *aFolder, int32_t aNewCount); + nsresult GetFirstFolderWithNewMail(nsIMsgFolder* aFolder, nsCString& aFolderURI); + nsresult BadgeDockIcon(); + nsresult RestoreDockIcon(); + nsresult BounceDockIcon(); + nsresult GetNewMailAuthors(nsIMsgFolder* aFolder, nsString& aAuthors, int32_t aNewCount, int32_t* aNotDisplayed); + + int32_t mUnreadTotal; + int32_t mUnreadChat; +}; + +#endif // __nsMessengerOSXIntegration_h diff --git a/mailnews/base/src/nsMessengerOSXIntegration.mm b/mailnews/base/src/nsMessengerOSXIntegration.mm new file mode 100644 index 0000000000..a38716e179 --- /dev/null +++ b/mailnews/base/src/nsMessengerOSXIntegration.mm @@ -0,0 +1,700 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nscore.h" +#include "nsMsgUtils.h" +#include "nsArrayUtils.h" +#include "nsMessengerOSXIntegration.h" +#include "nsIMsgMailSession.h" +#include "nsIMsgIncomingServer.h" +#include "nsIMsgIdentity.h" +#include "nsIMsgAccount.h" +#include "nsIMsgFolder.h" +#include "nsCOMPtr.h" +#include "nsMsgBaseCID.h" +#include "nsMsgFolderFlags.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIDirectoryService.h" +#include "MailNewsTypes.h" +#include "nsIWindowMediator.h" +#include "nsIDOMChromeWindow.h" +#include "mozIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDocShell.h" +#include "nsIBaseWindow.h" +#include "nsIWidget.h" +#include "nsIObserverService.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIMessengerWindowService.h" +#include "prprf.h" +#include "nsIAlertsService.h" +#include "nsIStringBundle.h" +#include "nsToolkitCompsCID.h" +#include "nsIMsgDatabase.h" +#include "nsIMsgHdr.h" +#include "nsISupportsPrimitives.h" +#include "nsIWindowWatcher.h" +#include "nsMsgLocalCID.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsIMsgWindow.h" +#include "nsIMsgAccountManager.h" +#include "nsIMessenger.h" +#include "nsObjCExceptions.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "mozINewMailNotificationService.h" +#include "mozilla/mailnews/MimeHeaderParser.h" + +#include +#import + +#define kBiffAnimateDockIconPref "mail.biff.animate_dock_icon" +#define kMaxDisplayCount 10 + +using namespace mozilla::mailnews; + +// HACK: Limitations in Focus/SetFocus on Mac (see bug 465446) +nsresult FocusAppNative() +{ + ProcessSerialNumber psn; + + if (::GetCurrentProcess(&psn) != 0) + return NS_ERROR_FAILURE; + + if (::SetFrontProcess(&psn) != 0) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +static void openMailWindow(const nsCString& aUri) +{ + nsresult rv; + nsCOMPtr mailSession ( do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr topMostMsgWindow; + rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(topMostMsgWindow)); + if (topMostMsgWindow) + { + if (!aUri.IsEmpty()) + { + nsCOMPtr msgUri(do_CreateInstance(NS_MAILBOXURL_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return; + + rv = msgUri->SetSpec(aUri); + if (NS_FAILED(rv)) + return; + + bool isMessageUri = false; + msgUri->GetIsMessageUri(&isMessageUri); + if (isMessageUri) + { + nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return; + + // SeaMonkey only supports message uris, whereas Thunderbird only + // supports message headers. This should be simplified/removed when + // bug 507593 is implemented. +#ifdef MOZ_SUITE + nsCOMPtr newWindow; + wwatch->OpenWindow(0, "chrome://messenger/content/messageWindow.xul", + "_blank", "all,chrome,dialog=no,status,toolbar", msgUri, + getter_AddRefs(newWindow)); +#else + nsCOMPtr messenger(do_CreateInstance(NS_MESSENGER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return; + + nsCOMPtr msgHdr; + messenger->MsgHdrFromURI(aUri, getter_AddRefs(msgHdr)); + if (msgHdr) + { + nsCOMPtr newWindow; + wwatch->OpenWindow(0, "chrome://messenger/content/messageWindow.xul", + "_blank", "all,chrome,dialog=no,status,toolbar", msgHdr, + getter_AddRefs(newWindow)); + } +#endif + } + else + { + nsCOMPtr windowCommands; + topMostMsgWindow->GetWindowCommands(getter_AddRefs(windowCommands)); + if (windowCommands) + windowCommands->SelectFolder(aUri); + } + } + + FocusAppNative(); + nsCOMPtr domWindow; + topMostMsgWindow->GetDomWindow(getter_AddRefs(domWindow)); + if (domWindow) { + nsCOMPtr privateWindow = nsPIDOMWindowOuter::From(domWindow); + privateWindow->Focus(); + } + } + else + { + // the user doesn't have a mail window open already so open one for them... + nsCOMPtr messengerWindowService = + do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID); + // if we want to preselect the first account with new mail, + // here is where we would try to generate a uri to pass in + // (and add code to the messenger window service to make that work) + if (messengerWindowService) + messengerWindowService->OpenMessengerWindowWithUri( + "mail:3pane", aUri.get(), nsMsgKey_None); + } +} + +nsMessengerOSXIntegration::nsMessengerOSXIntegration() +{ + mBiffStateAtom = MsgGetAtom("BiffState"); + mNewMailReceivedAtom = MsgGetAtom("NewMailReceived"); + mUnreadTotal = 0; +} + +nsMessengerOSXIntegration::~nsMessengerOSXIntegration() +{ + RestoreDockIcon(); +} + +NS_IMPL_ADDREF(nsMessengerOSXIntegration) +NS_IMPL_RELEASE(nsMessengerOSXIntegration) + +NS_INTERFACE_MAP_BEGIN(nsMessengerOSXIntegration) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMessengerOSIntegration) + NS_INTERFACE_MAP_ENTRY(nsIMessengerOSIntegration) + NS_INTERFACE_MAP_ENTRY(nsIFolderListener) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(mozINewMailListener) +NS_INTERFACE_MAP_END + + +nsresult +nsMessengerOSXIntegration::Init() +{ + nsresult rv; + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + return observerService->AddObserver(this, "mail-startup-done", false); +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemPropertyChanged(nsIMsgFolder *, nsIAtom *, char const *, char const *) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemUnicharPropertyChanged(nsIMsgFolder *, nsIAtom *, const char16_t *, const char16_t *) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemRemoved(nsIMsgFolder *, nsISupports *) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) +{ + if (!strcmp(aTopic, "alertfinished")) + return OnAlertFinished(); + + if (!strcmp(aTopic, "alertclickcallback")) + return OnAlertClicked(aData); + +#ifdef MOZ_SUITE + // SeaMonkey does most of the GUI work in JS code when clicking on a mail + // notification, so it needs an extra function here + if (!strcmp(aTopic, "alertclicksimplecallback")) + return OnAlertClickedSimple(); +#endif + + if (!strcmp(aTopic, "mail-startup-done")) { + nsresult rv; + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + observerService->RemoveObserver(this, "mail-startup-done"); + + nsCOMPtr pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + } + + // Register with the new mail service for changes to the unread message count + nsCOMPtr newmail + = do_GetService(MOZ_NEWMAILNOTIFICATIONSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); // This should really be an assert with a helpful message + rv = newmail->AddListener(this, mozINewMailNotificationService::count); + NS_ENSURE_SUCCESS(rv, rv); // This should really be an assert with a helpful message + + // Get the initial unread count. Ignore return value; if code above didn't fail, this won't + rv = newmail->GetMessageCount(&mUnreadTotal); + BadgeDockIcon(); + + // register with the mail sesson for folder events + // we care about new count, biff status + nsCOMPtr mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return mailSession->AddFolderListener(this, nsIFolderListener::boolPropertyChanged | nsIFolderListener::intPropertyChanged); + } + + return NS_OK; +} + +nsresult +nsMessengerOSXIntegration::GetStringBundle(nsIStringBundle **aBundle) +{ + NS_ENSURE_ARG_POINTER(aBundle); + nsresult rv; + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); + nsCOMPtr bundle; + if (bundleService && NS_SUCCEEDED(rv)) + bundleService->CreateBundle("chrome://messenger/locale/messenger.properties", getter_AddRefs(bundle)); + bundle.swap(*aBundle); + return rv; +} + +void +nsMessengerOSXIntegration::FillToolTipInfo(nsIMsgFolder *aFolder, int32_t aNewCount) +{ + if (aFolder) + { + nsString authors; + int32_t numNotDisplayed; + nsresult rv = GetNewMailAuthors(aFolder, authors, aNewCount, &numNotDisplayed); + + // If all senders are vetoed, the authors string will be empty. + if (NS_FAILED(rv) || authors.IsEmpty()) + return; + + // If this isn't the root folder, get it so we can report for it. + // GetRootFolder always returns the server's root, so calling on the root itself is fine. + nsCOMPtr rootFolder; + aFolder->GetRootFolder(getter_AddRefs(rootFolder)); + if (!rootFolder) + return; + + nsString accountName; + rootFolder->GetPrettiestName(accountName); + + nsCOMPtr bundle; + GetStringBundle(getter_AddRefs(bundle)); + if (bundle) + { + nsAutoString numNewMsgsText; + numNewMsgsText.AppendInt(aNewCount); + nsString finalText; + nsCString uri; + aFolder->GetURI(uri); + + if (numNotDisplayed > 0) + { + nsAutoString numNotDisplayedText; + numNotDisplayedText.AppendInt(numNotDisplayed); + const char16_t *formatStrings[3] = { numNewMsgsText.get(), authors.get(), numNotDisplayedText.get() }; + bundle->FormatStringFromName(u"macBiffNotification_messages_extra", + formatStrings, + 3, + getter_Copies(finalText)); + } + else + { + const char16_t *formatStrings[2] = { numNewMsgsText.get(), authors.get() }; + + if (aNewCount == 1) + { + bundle->FormatStringFromName(u"macBiffNotification_message", + formatStrings, + 2, + getter_Copies(finalText)); + // Since there is only 1 message, use the most recent mail's URI instead of the folder's + nsCOMPtr db; + rv = aFolder->GetMsgDatabase(getter_AddRefs(db)); + if (NS_SUCCEEDED(rv) && db) + { + uint32_t numNewKeys; + uint32_t *newMessageKeys; + rv = db->GetNewList(&numNewKeys, &newMessageKeys); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr hdr; + rv = db->GetMsgHdrForKey(newMessageKeys[numNewKeys - 1], + getter_AddRefs(hdr)); + if (NS_SUCCEEDED(rv) && hdr) + aFolder->GetUriForMsg(hdr, uri); + } + NS_Free(newMessageKeys); + } + } + else + bundle->FormatStringFromName(u"macBiffNotification_messages", + formatStrings, + 2, + getter_Copies(finalText)); + } + ShowAlertMessage(accountName, finalText, uri); + } // if we got a bundle + } // if we got a folder +} + +nsresult +nsMessengerOSXIntegration::ShowAlertMessage(const nsAString& aAlertTitle, + const nsAString& aAlertText, + const nsACString& aFolderURI) +{ + nsresult rv; + + nsCOMPtr alertsService (do_GetService(NS_ALERTSERVICE_CONTRACTID, &rv)); + // If we have an nsIAlertsService implementation, use it: + if (NS_SUCCEEDED(rv)) + { + alertsService->ShowAlertNotification(EmptyString(), + aAlertTitle, aAlertText, true, + NS_ConvertASCIItoUTF16(aFolderURI), + this, EmptyString(), + NS_LITERAL_STRING("auto"), + EmptyString(), EmptyString(), + nullptr, + false, + false); + } + + BounceDockIcon(); + + if (NS_FAILED(rv)) + OnAlertFinished(); + + return rv; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemIntPropertyChanged(nsIMsgFolder *aFolder, + nsIAtom *aProperty, + int64_t aOldValue, + int64_t aNewValue) +{ + // if we got new mail show an alert + if (aNewValue == nsIMsgFolder::nsMsgBiffState_NewMail) + { + bool performingBiff = false; + nsCOMPtr server; + aFolder->GetServer(getter_AddRefs(server)); + if (server) + server->GetPerformingBiff(&performingBiff); + if (!performingBiff) + return NS_OK; // kick out right now... + + // Biff happens for the root folder, but we want info for the child with new mail + nsCString folderUri; + GetFirstFolderWithNewMail(aFolder, folderUri); + nsCOMPtr childFolder; + nsresult rv = aFolder->GetChildWithURI(folderUri, true, true, + getter_AddRefs(childFolder)); + if (NS_FAILED(rv) || !childFolder) + return NS_ERROR_FAILURE; + + int32_t numNewMessages = 0; + childFolder->GetNumNewMessages(true, &numNewMessages); + FillToolTipInfo(childFolder, numNewMessages); + } + else if (mNewMailReceivedAtom == aProperty) + { + FillToolTipInfo(aFolder, aNewValue); + } + return NS_OK; +} + +nsresult +nsMessengerOSXIntegration::OnAlertClicked(const char16_t* aAlertCookie) +{ + openMailWindow(NS_ConvertUTF16toUTF8(aAlertCookie)); + return NS_OK; +} + +#ifdef MOZ_SUITE +nsresult +nsMessengerOSXIntegration::OnAlertClickedSimple() +{ + // SeaMonkey only function; only focus the app here, rest of the work will + // be done in suite/mailnews/mailWidgets.xml + FocusAppNative(); + return NS_OK; +} +#endif + +nsresult +nsMessengerOSXIntegration::OnAlertFinished() +{ + return NS_OK; +} + +nsresult +nsMessengerOSXIntegration::BounceDockIcon() +{ + nsresult rv; + nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + bool bounceDockIcon = false; + rv = prefBranch->GetBoolPref(kBiffAnimateDockIconPref, &bounceDockIcon); + NS_ENSURE_SUCCESS(rv, rv); + + if (!bounceDockIcon) + return NS_OK; + + nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); + if (mediator) + { + nsCOMPtr domWindow; + mediator->GetMostRecentWindow(u"mail:3pane", getter_AddRefs(domWindow)); + if (domWindow) + { + nsCOMPtr chromeWindow(do_QueryInterface(domWindow)); + chromeWindow->GetAttention(); + } + } + return NS_OK; +} + +nsresult +nsMessengerOSXIntegration::RestoreDockIcon() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + id tile = [[NSApplication sharedApplication] dockTile]; + [tile setBadgeLabel: nil]; + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +nsresult +nsMessengerOSXIntegration::BadgeDockIcon() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + int32_t unreadCount = mUnreadTotal; + // If count is less than one, we should restore the original dock icon. + if (unreadCount < 1) + { + RestoreDockIcon(); + return NS_OK; + } + + // Draw the number, first giving extensions a chance to modify. + // Extensions might wish to transform "1000" into "100+" or some + // other short string. Getting back the empty string will cause + // nothing to be drawn and us to return early. + nsresult rv; + nsCOMPtr os + (do_GetService("@mozilla.org/observer-service;1", &rv)); + if (NS_FAILED(rv)) + { + RestoreDockIcon(); + return rv; + } + + nsCOMPtr str + (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + { + RestoreDockIcon(); + return rv; + } + + nsAutoString total; + total.AppendInt(unreadCount); + str->SetData(total); + os->NotifyObservers(str, "before-unread-count-display", + total.get()); + nsAutoString badgeString; + str->GetData(badgeString); + if (badgeString.IsEmpty()) + { + RestoreDockIcon(); + return NS_OK; + } + + id tile = [[NSApplication sharedApplication] dockTile]; + [tile setBadgeLabel:[NSString stringWithFormat:@"%S", (const unichar*)badgeString.get()]]; + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, nsIAtom *property, uint32_t oldFlag, uint32_t newFlag) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemAdded(nsIMsgFolder *, nsISupports *) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemBoolPropertyChanged(nsIMsgFolder *aItem, + nsIAtom *aProperty, + bool aOldValue, + bool aNewValue) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMessengerOSXIntegration::OnItemEvent(nsIMsgFolder *, nsIAtom *) +{ + return NS_OK; +} + +nsresult +nsMessengerOSXIntegration::GetNewMailAuthors(nsIMsgFolder* aFolder, + nsString& aAuthors, + int32_t aNewCount, + int32_t* aNotDisplayed) +{ + // Get a list of names or email addresses for the folder's authors + // with new mail. Note that we only process the most recent "new" + // mail (aNewCount), working from most recently added. Duplicates + // are removed, and names are displayed to a set limit + // (kMaxDisplayCount) with the remaining count being returned in + // aNotDisplayed. Extension developers can listen for + // "newmail-notification-requested" and then make a decision about + // including a given author or not. As a result, it is possible that + // the resulting length of aAuthors will be 0. + nsCOMPtr db; + nsresult rv = aFolder->GetMsgDatabase(getter_AddRefs(db)); + uint32_t numNewKeys = 0; + if (NS_SUCCEEDED(rv) && db) + { + nsCOMPtr os = + do_GetService("@mozilla.org/observer-service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Get proper l10n list separator -- ", " in English + nsCOMPtr bundle; + GetStringBundle(getter_AddRefs(bundle)); + if (!bundle) + return NS_ERROR_FAILURE; + + uint32_t *newMessageKeys; + rv = db->GetNewList(&numNewKeys, &newMessageKeys); + if (NS_SUCCEEDED(rv)) + { + nsString listSeparator; + bundle->GetStringFromName(u"macBiffNotification_separator", getter_Copies(listSeparator)); + + int32_t displayed = 0; + for (int32_t i = numNewKeys - 1; i >= 0; i--, aNewCount--) + { + if (0 == aNewCount || displayed == kMaxDisplayCount) + break; + + nsCOMPtr hdr; + rv = db->GetMsgHdrForKey(newMessageKeys[i], + getter_AddRefs(hdr)); + if (NS_SUCCEEDED(rv) && hdr) + { + nsString author; + rv = hdr->GetMime2DecodedAuthor(author); + if (NS_FAILED(rv)) + continue; + + nsString name; + ExtractName(DecodedHeader(author), name); + + // Give extensions a chance to suppress notifications for this author + nsCOMPtr notify = + do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID); + + notify->SetData(true); + os->NotifyObservers(notify, "newmail-notification-requested", + author.get()); + + bool includeSender; + notify->GetData(&includeSender); + + // Don't add unwanted or duplicate names + if (includeSender && aAuthors.Find(name, true) == -1) + { + if (displayed > 0) + aAuthors.Append(listSeparator); + aAuthors.Append(name); + displayed++; + } + } + } + } + NS_Free(newMessageKeys); + } + *aNotDisplayed = aNewCount; + return rv; +} + +nsresult +nsMessengerOSXIntegration::GetFirstFolderWithNewMail(nsIMsgFolder* aFolder, nsCString& aFolderURI) +{ + // Find the subfolder in aFolder with new mail and return the folderURI + if (aFolder) + { + nsCOMPtr msgFolder; + // enumerate over the folders under this root folder till we find one with new mail.... + nsCOMPtr allFolders; + nsresult rv = aFolder->GetDescendants(getter_AddRefs(allFolders)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr enumerator; + rv = allFolders->Enumerate(getter_AddRefs(enumerator)); + if (NS_SUCCEEDED(rv) && enumerator) + { + nsCOMPtr supports; + int32_t numNewMessages = 0; + bool hasMore = false; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) + { + rv = enumerator->GetNext(getter_AddRefs(supports)); + if (NS_SUCCEEDED(rv) && supports) + { + msgFolder = do_QueryInterface(supports, &rv); + if (msgFolder) + { + numNewMessages = 0; + msgFolder->GetNumNewMessages(false, &numNewMessages); + if (numNewMessages) + break; // kick out of the while loop + } + } // if we have a folder + } // if we have more potential folders to enumerate + } // if enumerator + + if (msgFolder) + msgFolder->GetURI(aFolderURI); + } + + return NS_OK; +} + +/* + * Method implementations for mozINewMailListener + */ +NS_IMETHODIMP +nsMessengerOSXIntegration::OnCountChanged(uint32_t count) +{ + mUnreadTotal = count; + BadgeDockIcon(); + return NS_OK; +} diff --git a/mailnews/build/moz.build b/mailnews/build/moz.build index 9561fd33d8..9620e8f3d4 100644 --- a/mailnews/build/moz.build +++ b/mailnews/build/moz.build @@ -35,6 +35,10 @@ if CONFIG['OS_ARCH'] == 'WINNT': else: OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + OS_LIBS += CONFIG['TK_LIBS'] + OS_LIBS += ['-framework Cocoa'] + LOCAL_INCLUDES += [ '/mailnews/addrbook/src', '/mailnews/base/search/src', diff --git a/mailnews/compose/src/moz.build b/mailnews/compose/src/moz.build index 831a0340f4..dcb9960a66 100644 --- a/mailnews/compose/src/moz.build +++ b/mailnews/compose/src/moz.build @@ -35,6 +35,16 @@ SOURCES += [ 'nsURLFetcher.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'nsMsgAppleDoubleEncode.cpp', + 'nsMsgAppleEncode.cpp', + ] + EXPORTS += [ + 'nsMsgAppleCodes.h', + 'nsMsgAppleDouble.h', + ] + EXTRA_COMPONENTS += [ 'nsSMTPProtocolHandler.js', 'nsSMTPProtocolHandler.manifest', diff --git a/mailnews/compose/src/nsMsgAppleCodes.h b/mailnews/compose/src/nsMsgAppleCodes.h new file mode 100644 index 0000000000..d8ca2f327c --- /dev/null +++ b/mailnews/compose/src/nsMsgAppleCodes.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +** AD_Codes.h +** +** --------------- +** +** Head file for Apple Decode/Encode essential codes. +** +** +*/ + +#ifndef ad_codes_h +#define ad_codes_h + +/* +** applefile definitions used +*/ +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#endif + +#define APPLESINGLE_MAGIC 0x00051600L +#define APPLEDOUBLE_MAGIC 0x00051607L +#define VERSION 0x00020000 + +#define NUM_ENTRIES 6 + +#define ENT_DFORK 1L +#define ENT_RFORK 2L +#define ENT_NAME 3L +#define ENT_COMMENT 4L +#define ENT_DATES 8L +#define ENT_FINFO 9L +#define CONVERT_TIME 1265437696L + +/* +** data type used in the encoder/decoder. +*/ +typedef struct ap_header +{ + int32_t magic; + int32_t version; + char fill[16]; + int16_t entries; + +} ap_header; + +typedef struct ap_entry +{ + int32_t id; + int32_t offset; + int32_t length; + +} ap_entry; + +typedef struct ap_dates +{ + int32_t create, modify, backup, access; + +} ap_dates; + +typedef struct myFInfo /* the mac FInfo structure for the cross platform. */ +{ + int32_t fdType, fdCreator; + int16_t fdFlags; + int32_t fdLocation; /* it really should be a pointer, but just a place-holder */ + int16_t fdFldr; + +} myFInfo; + +PR_BEGIN_EXTERN_C +/* +** string utils. +*/ +int write_stream(appledouble_encode_object *p_ap_encode_obj, const char *s,int len); + +int fill_apple_mime_header(appledouble_encode_object *p_ap_encode_obj); +int ap_encode_file_infor(appledouble_encode_object *p_ap_encode_obj); +int ap_encode_header(appledouble_encode_object* p_ap_encode_obj, bool firstTime); +int ap_encode_data( appledouble_encode_object* p_ap_encode_obj, bool firstTime); + +/* +** the prototypes for the ap_decoder. +*/ +int fetch_a_line(appledouble_decode_object* p_ap_decode_obj, char *buff); +int ParseFileHeader(appledouble_decode_object* p_ap_decode_obj); +int ap_seek_part_start(appledouble_decode_object* p_ap_decode_obj); +void parse_param(char *p, char **param, char**define, char **np); +int ap_seek_to_boundary(appledouble_decode_object* p_ap_decode_obj, bool firstime); +int ap_parse_header(appledouble_decode_object* p_ap_decode_obj,bool firstime); +int ap_decode_file_infor(appledouble_decode_object* p_ap_decode_obj); +int ap_decode_process_header(appledouble_decode_object* p_ap_decode_obj, bool firstime); +int ap_decode_process_data( appledouble_decode_object* p_ap_decode_obj, bool firstime); + +PR_END_EXTERN_C + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#endif + +#endif /* ad_codes_h */ diff --git a/mailnews/compose/src/nsMsgAppleDouble.h b/mailnews/compose/src/nsMsgAppleDouble.h new file mode 100644 index 0000000000..f4ae934add --- /dev/null +++ b/mailnews/compose/src/nsMsgAppleDouble.h @@ -0,0 +1,207 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +* AppleDouble.h +* ------------- +* +* The header file for a stream based apple single/double encodor/decodor. +* +* 2aug95 mym +* +*/ + + +#ifndef AppleDouble_h +#define AppleDouble_h + +#include "msgCore.h" +#include "nsComposeStrings.h" +#include "nsIOutputStream.h" +#include "nsCOMPtr.h" + +#include + +#define NOERR 0 +#define errDone 1 + /* Done with current operation. */ +#define errEOB 2 + /* End of a buffer. */ +#define errEOP 3 + /* End of a Part. */ + + +#define errFileOpen NS_ERROR_GET_CODE(NS_MSG_UNABLE_TO_OPEN_TMP_FILE) +#define errFileWrite -202 /*Error writing temporary file.*/ +#define errUsrCancel -2 /*MK_INTERRUPTED */ +#define errDecoding -1 + +/* +** The envirment block data type. +*/ +enum +{ + kInit, + kDoingHeaderPortion, + kDoneHeaderPortion, + kDoingDataPortion, + kDoneDataPortion +}; + +typedef struct _appledouble_encode_object +{ + char fname[256]; + FSIORefNum fileId; /* the id for the open file (data/resource fork) */ + + int state; + int text_file_type; /* if the file has a text file type with it. */ + char *boundary; /* the boundary string. */ + + int status; /* the error code if anyerror happens. */ + char b_overflow[200]; + int s_overflow; + + int state64; /* the left over state of base64 enocding */ + int ct; /* the character count of base64 encoding */ + int c1, c2; /* the left of the last base64 encoding */ + + char *outbuff; /* the outbuff by the caller. */ + int s_outbuff; /* the size of the buffer. */ + int pos_outbuff; /* the offset in the current buffer. */ + +} appledouble_encode_object; + +/* The possible content transfer encodings */ + +enum +{ + kEncodeNone, + kEncodeQP, + kEncodeBase64, + kEncodeUU +}; + +enum +{ + kGeneralMine, + kAppleDouble, + kAppleSingle +}; + +enum +{ + kInline, + kDontCare +}; + +enum +{ + kHeaderPortion, + kDataPortion +}; + +/* the decode states. */ +enum +{ + kBeginParseHeader = 3, + kParsingHeader, + kBeginSeekBoundary, + kSeekingBoundary, + kBeginHeaderPortion, + kProcessingHeaderPortion, + kBeginDataPortion, + kProcessingDataPortion, + kFinishing +}; + +/* uuencode states */ +enum +{ + kWaitingForBegin = (int) 0, + kBegin, + kMainBody, + kEnd +}; + +typedef struct _appledouble_decode_object +{ + int is_binary; + int is_apple_single; /* if the object encoded is in apple single */ + int write_as_binhex; + + int messagetype; + char* boundary0; /* the boundary for the enclosure. */ + int deposition; /* the deposition. */ + int encoding; /* the encoding method. */ + int which_part; + + char fname[256]; + // nsIOFileStream *fileSpec; /* the stream for data fork work. */ + + int state; + + int rksize; /* the resource fork size count. */ + int dksize; /* the data fork size count. */ + + int status; /* the error code if anyerror happens. */ + char b_leftover[256]; + int s_leftover; + + int encode; /* the encode type of the message. */ + int state64; /* the left over state of base64 enocding */ + int left; /* the character count of base64 encoding */ + int c[4]; /* the left of the last base64 encoding */ + int uu_starts_line; /* is decoder at the start of a line? (uuencode) */ + int uu_state; /* state w/r/t the uuencode body */ + int uu_bytes_written; /* bytes written from the current tuple (uuencode) */ + int uu_line_bytes; /* encoded bytes remaining in the current line (uuencode) */ + + char *inbuff; /* the outbuff by the caller. */ + int s_inbuff; /* the size of the buffer. */ + int pos_inbuff; /* the offset in the current buffer. */ + + + nsCOMPtr tmpFile; /* the temp file to hold the decode data fork */ + /* when doing the binhex exporting. */ + nsCOMPtr tmpFileStream; /* The output File Stream */ + int32_t data_size; /* the size of the data in the tmp file. */ + +} appledouble_decode_object; + + +/* +** The protypes. +*/ + +PR_BEGIN_EXTERN_C + +int ap_encode_init(appledouble_encode_object *p_ap_encode_obj, + const char* fname, + char* separator); + +int ap_encode_next(appledouble_encode_object* p_ap_encode_obj, + char *to_buff, + int32_t buff_size, + int32_t* real_size); + +int ap_encode_end(appledouble_encode_object* p_ap_encode_obj, + bool is_aborting); + +int ap_decode_init(appledouble_decode_object* p_ap_decode_obj, + bool is_apple_single, + bool write_as_bin_hex, + void *closure); + +int ap_decode_next(appledouble_decode_object* p_ap_decode_obj, + char *in_buff, + int32_t buff_size); + +int ap_decode_end(appledouble_decode_object* p_ap_decode_obj, + bool is_aborting); + +PR_END_EXTERN_C + +#endif diff --git a/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp b/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp new file mode 100644 index 0000000000..4d71781233 --- /dev/null +++ b/mailnews/compose/src/nsMsgAppleDoubleEncode.cpp @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +* +* apple-double.c +* -------------- +* +* The codes to do apple double encoding/decoding. +* +* 02aug95 mym created. +* +*/ +#include "nsID.h" +#include "nscore.h" +#include "nsStringGlue.h" +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleCodes.h" +#include "nsMsgCompUtils.h" +#include "nsCExternalHandlerService.h" +#include "nsIMIMEService.h" +#include "nsMimeTypes.h" +#include "prmem.h" +#include "nsNetUtil.h" + + +void +MacGetFileType(nsIFile *fs, + bool *useDefault, + char **fileType, + char **encoding) +{ + if ((fs == NULL) || (fileType == NULL) || (encoding == NULL)) + return; + + bool exists = false; + fs->Exists(&exists); + if (!exists) + return; + + *useDefault = TRUE; + *fileType = NULL; + *encoding = NULL; + + nsCOMPtr macFile = do_QueryInterface(fs); + FSRef fsRef; + FSCatalogInfo catalogInfo; + OSErr err = errFileOpen; + if (NS_SUCCEEDED(macFile->GetFSRef(&fsRef))) + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr); + + if ( (err != noErr) || (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT') ) + *fileType = strdup(APPLICATION_OCTET_STREAM); + else + { + // At this point, we should call the mime service and + // see what we can find out? + nsresult rv; + nsCOMPtr tURI; + if (NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(tURI), fs)) && tURI) + { + nsCOMPtr mimeFinder (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv) && mimeFinder) + { + nsAutoCString mimeType; + rv = mimeFinder->GetTypeFromURI(tURI, mimeType); + if (NS_SUCCEEDED(rv)) + { + *fileType = ToNewCString(mimeType); + return; + } + } + } + + // If we hit here, return something...default to this... + *fileType = strdup(APPLICATION_OCTET_STREAM); + } +} + +//#pragma cplusplus reset + +/* +* ap_encode_init +* -------------- +* +* Setup the encode envirment +*/ + +int ap_encode_init( appledouble_encode_object *p_ap_encode_obj, + const char *fname, + char *separator) +{ + nsCOMPtr myFile; + NS_NewNativeLocalFile(nsDependentCString(fname), true, getter_AddRefs(myFile)); + bool exists; + if (myFile && NS_SUCCEEDED(myFile->Exists(&exists)) && !exists) + return -1; + + nsCOMPtr macFile = do_QueryInterface(myFile); + nsAutoCString path; + macFile->GetNativePath(path); + + memset(p_ap_encode_obj, 0, sizeof(appledouble_encode_object)); + + /* + ** Fill out the source file inforamtion. + */ + memcpy(p_ap_encode_obj->fname, path.get(), path.Length()); + p_ap_encode_obj->fname[path.Length()] = '\0'; + + p_ap_encode_obj->boundary = strdup(separator); + return noErr; +} + +/* +** ap_encode_next +** -------------- +** +** return : +** noErr : everything is ok +** errDone : when encoding is done. +** errors : otherwise. +*/ +int ap_encode_next( + appledouble_encode_object* p_ap_encode_obj, + char *to_buff, + int32_t buff_size, + int32_t* real_size) +{ + int status; + + /* + ** install the out buff now. + */ + p_ap_encode_obj->outbuff = to_buff; + p_ap_encode_obj->s_outbuff = buff_size; + p_ap_encode_obj->pos_outbuff = 0; + + /* + ** first copy the outstandind data in the overflow buff to the out buffer. + */ + if (p_ap_encode_obj->s_overflow) + { + status = write_stream(p_ap_encode_obj, + (const char*)(p_ap_encode_obj->b_overflow), + p_ap_encode_obj->s_overflow); + if (status != noErr) + return status; + + p_ap_encode_obj->s_overflow = 0; + } + + /* + ** go the next processing stage based on the current state. + */ + switch (p_ap_encode_obj->state) + { + case kInit: + /* + ** We are in the starting position, fill out the header. + */ + status = fill_apple_mime_header(p_ap_encode_obj); + if (status != noErr) + break; /* some error happens */ + + p_ap_encode_obj->state = kDoingHeaderPortion; + status = ap_encode_header(p_ap_encode_obj, true); + /* it is the first time to calling */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneHeaderPortion; + } + else + { + break; /* we need more work on header portion. */ + } + + /* + ** we are done with the header, so let's go to the data port. + */ + p_ap_encode_obj->state = kDoingDataPortion; + status = ap_encode_data(p_ap_encode_obj, true); + /* it is first time call do data portion */ + + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoingHeaderPortion: + + status = ap_encode_header(p_ap_encode_obj, false); + /* continue with the header portion. */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneHeaderPortion; + } + else + { + break; /* we need more work on header portion. */ + } + + /* + ** start the data portion. + */ + p_ap_encode_obj->state = kDoingDataPortion; + status = ap_encode_data(p_ap_encode_obj, true); + /* it is the first time calling */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoingDataPortion: + + status = ap_encode_data(p_ap_encode_obj, false); + /* it is not the first time */ + + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoneDataPortion: + status = errDone; /* we are really done. */ + + break; + } + + *real_size = p_ap_encode_obj->pos_outbuff; + return status; +} + +/* +** ap_encode_end +** ------------- +** +** clear the apple encoding. +*/ + +int ap_encode_end( + appledouble_encode_object *p_ap_encode_obj, + bool is_aborting) +{ + /* + ** clear up the apple doubler. + */ + if (p_ap_encode_obj == NULL) + return noErr; + + if (p_ap_encode_obj->fileId) /* close the file if it is open. */ + ::FSCloseFork(p_ap_encode_obj->fileId); + + PR_FREEIF(p_ap_encode_obj->boundary); /* the boundary string. */ + + return noErr; +} diff --git a/mailnews/compose/src/nsMsgAppleEncode.cpp b/mailnews/compose/src/nsMsgAppleEncode.cpp new file mode 100644 index 0000000000..27e39a8cda --- /dev/null +++ b/mailnews/compose/src/nsMsgAppleEncode.cpp @@ -0,0 +1,703 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * + * apple_double_encode.c + * --------------------- + * + * The routines doing the Apple Double Encoding. + * + * 2aug95 mym Created. + * + */ + +#include "nscore.h" +#include "nsStringGlue.h" +#include "nsMimeTypes.h" +#include "prprf.h" +#include "nsServiceManagerUtils.h" +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleCodes.h" +#include "nsILocalFileMac.h" + +/* +** Local Functions prototypes. +*/ +static int output64chunk( appledouble_encode_object* p_ap_encode_obj, + int c1, int c2, int c3, int pads); + +static int to64(appledouble_encode_object* p_ap_encode_obj, + char *p, + int in_size); + +static int finish64(appledouble_encode_object* p_ap_encode_obj); + + +#define BUFF_LEFT(p) ((p)->s_outbuff - (p)->pos_outbuff) + +/* +** write_stream. +*/ +int write_stream( + appledouble_encode_object *p_ap_encode_obj, + const char *out_string, + int len) +{ + if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff) + { + memcpy(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff, + out_string, + len); + p_ap_encode_obj->pos_outbuff += len; + return noErr; + } + else + { + /* + ** If the buff doesn't have enough space, use the overflow buffer then. + */ + int s_len = p_ap_encode_obj->s_outbuff - p_ap_encode_obj->pos_outbuff; + + memcpy(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff, + out_string, + s_len); + memcpy(p_ap_encode_obj->b_overflow + p_ap_encode_obj->s_overflow, + out_string + s_len, + p_ap_encode_obj->s_overflow += (len - s_len)); + p_ap_encode_obj->pos_outbuff += s_len; + return errEOB; + } +} + +int fill_apple_mime_header( + appledouble_encode_object *p_ap_encode_obj) +{ + int status; + + char tmpstr[266]; + +#if 0 +// strcpy(tmpstr, "Content-Type: multipart/mixed; boundary=\"-\"\n\n---\n"); +// status = write_stream(p_ap_encode_env, +// tmpstr, +// strlen(tmpstr)); +// if (status != noErr) +// return status; + + PR_snprintf(tmpstr, sizeof(tmpstr), + "Content-Type: multipart/appledouble; boundary=\"=\"; name=\""); + status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr)); + if (status != noErr) + return status; + + status = write_stream(p_ap_encode_obj, + p_ap_encode_obj->fname, + strlen(p_ap_encode_obj->fname)); + if (status != noErr) + return status; + + PR_snprintf(tmpstr, sizeof(tmpstr), + "\"\r\nContent-Disposition: inline; filename=\"%s\"\r\n\r\n\r\n--=\r\n", + p_ap_encode_obj->fname); +#endif /* 0 */ + PR_snprintf(tmpstr, sizeof(tmpstr), "--%s" CRLF, p_ap_encode_obj->boundary); + status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr)); + return status; +} + +int ap_encode_file_infor( + appledouble_encode_object *p_ap_encode_obj) +{ + ap_header head; + ap_entry entries[NUM_ENTRIES]; + ap_dates dates; + short i; + long comlen; + char comment[256]; + int status; + + nsCOMPtr resFile; + NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true, + getter_AddRefs(resFile)); + if (!resFile) + return errFileOpen; + + FSRef ref; + nsCOMPtr macFile = do_QueryInterface(resFile); + if (NS_FAILED(macFile->GetFSRef(&ref))) + return errFileOpen; + + FSCatalogInfo catalogInfo; + if (::FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr) != noErr) + { + return errFileOpen; + } + + /* get a file comment, if possible */ +#if 1 + // Carbon doesn't support GetWDInfo(). (Bug 555684) + + // not sure why working directories are needed here... + comlen = 0; +#else + long procID; + procID = 0; + GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID); + IOParam vinfo; + memset((void *) &vinfo, '\0', sizeof (vinfo)); + GetVolParmsInfoBuffer vp; + vinfo.ioCompletion = nil; + vinfo.ioVRefNum = fpb->ioVRefNum; + vinfo.ioBuffer = (Ptr) &vp; + vinfo.ioReqCount = sizeof (vp); + comlen = 0; + if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && + ((vp.vMAttrib >> bHasDesktopMgr) & 1)) + { + DTPBRec dtp; + memset((void *) &dtp, '\0', sizeof (dtp)); + dtp.ioVRefNum = fpb->ioVRefNum; + if (PBDTGetPath(&dtp) == noErr) + { + dtp.ioCompletion = nil; + dtp.ioDTBuffer = (Ptr) comment; + dtp.ioNamePtr = fpb->ioNamePtr; + dtp.ioDirID = fpb->ioFlParID; + if (PBDTGetCommentSync(&dtp) == noErr) + comlen = dtp.ioDTActCount; + } + } +#endif /* ! 1 */ + + /* write header */ +// head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC; + head.magic = APPLEDOUBLE_MAGIC; /* always do apple double */ + head.version = VERSION; + memset(head.fill, '\0', sizeof (head.fill)); + head.entries = NUM_ENTRIES - 1; + status = to64(p_ap_encode_obj, + (char *) &head, + sizeof (head)); + if (status != noErr) + return status; + + /* write entry descriptors */ + nsAutoCString leafname; + macFile->GetNativeLeafName(leafname); + entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries; + entries[0].id = ENT_NAME; + entries[0].length = leafname.Length(); + entries[1].id = ENT_FINFO; + entries[1].length = sizeof (FInfo) + sizeof (FXInfo); + entries[2].id = ENT_DATES; + entries[2].length = sizeof (ap_dates); + entries[3].id = ENT_COMMENT; + entries[3].length = comlen; + entries[4].id = ENT_RFORK; + entries[4].length = catalogInfo.rsrcLogicalSize; + entries[5].id = ENT_DFORK; + entries[5].length = catalogInfo.dataLogicalSize; + + /* correct the link in the entries. */ + for (i = 1; i < NUM_ENTRIES; ++i) + { + entries[i].offset = entries[i-1].offset + entries[i-1].length; + } + status = to64(p_ap_encode_obj, + (char *) entries, + sizeof (ap_entry) * head.entries); + if (status != noErr) + return status; + + /* write name */ + status = to64(p_ap_encode_obj, + (char *) leafname.get(), + leafname.Length()); + if (status != noErr) + return status; + + /* write finder info */ + status = to64(p_ap_encode_obj, + (char *) &catalogInfo.finderInfo, + sizeof (FInfo)); + if (status != noErr) + return status; + + status = to64(p_ap_encode_obj, + (char *) &catalogInfo.extFinderInfo, + sizeof (FXInfo)); + if (status != noErr) + return status; + + /* write dates */ + dates.create = catalogInfo.createDate.lowSeconds + CONVERT_TIME; + dates.modify = catalogInfo.contentModDate.lowSeconds + CONVERT_TIME; + dates.backup = catalogInfo.backupDate.lowSeconds + CONVERT_TIME; + dates.access = catalogInfo.accessDate.lowSeconds + CONVERT_TIME; + status = to64(p_ap_encode_obj, + (char *) &dates, + sizeof (ap_dates)); + if (status != noErr) + return status; + + /* write comment */ + if (comlen) + { + status = to64(p_ap_encode_obj, + comment, + comlen * sizeof(char)); + } + /* + ** Get some help information on deciding the file type. + */ + if (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT' || + ((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'text') + { + p_ap_encode_obj->text_file_type = true; + } + + return status; +} +/* +** ap_encode_header +** +** encode the file header and the resource fork. +** +*/ +int ap_encode_header( + appledouble_encode_object* p_ap_encode_obj, + bool firstime) +{ + char rd_buff[256]; + FSIORefNum fileId; + OSErr retval = noErr; + int status; + ByteCount inCount; + + if (firstime) + { + PL_strcpy(rd_buff, + "Content-Type: application/applefile\r\nContent-Transfer-Encoding: base64\r\n\r\n"); + status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff)); + if (status != noErr) + return status; + + status = ap_encode_file_infor(p_ap_encode_obj); + if (status != noErr) + return status; + + /* + ** preparing to encode the resource fork. + */ + nsCOMPtr myFile; + NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true, getter_AddRefs(myFile)); + if (!myFile) + return errFileOpen; + + FSRef ref; + nsCOMPtr macFile = do_QueryInterface(myFile); + if (NS_FAILED(macFile->GetFSRef(&ref))) + return errFileOpen; + + HFSUniStr255 forkName; + ::FSGetResourceForkName(&forkName); + retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &p_ap_encode_obj->fileId); + if (retval != noErr) + return retval; + } + + fileId = p_ap_encode_obj->fileId; + while (retval == noErr) + { + if (BUFF_LEFT(p_ap_encode_obj) < 400) + break; + + inCount = 0; + retval = ::FSReadFork(fileId, fsAtMark, 0, 256, rd_buff, &inCount); + if (inCount) + { + status = to64(p_ap_encode_obj, + rd_buff, + inCount); + if (status != noErr) + return status; + } + } + + if (retval == eofErr) + { + ::FSCloseFork(fileId); + p_ap_encode_obj->fileId = 0; + + status = finish64(p_ap_encode_obj); + if (status != noErr) + return status; + + /* + ** write out the boundary + */ + PR_snprintf(rd_buff, sizeof(rd_buff), + CRLF "--%s" CRLF, + p_ap_encode_obj->boundary); + + status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff)); + if (status == noErr) + status = errDone; + } + return status; +} + +#if 0 +// This is unused for now and Clang complains about that is it is ifdefed out +static void replace(char *p, int len, char frm, char to) +{ + for (; len > 0; len--, p++) + if (*p == frm) *p = to; +} +#endif + +/* Description of the various file formats and their magic numbers */ +struct magic +{ + const char *name; /* Name of the file format */ + const char *num; /* The magic number */ + int len; /* Length (0 means strlen(magicnum)) */ +}; + +/* The magic numbers of the file formats we know about */ +static struct magic magic[] = +{ + { "image/gif", "GIF", 0 }, + { "image/jpeg", "\377\330\377", 0 }, + { "video/mpeg", "\0\0\001\263", 4 }, + { "application/postscript", "%!", 0 }, +}; +static int num_magic = MOZ_ARRAY_LENGTH(magic); + +static const char *text_type = TEXT_PLAIN; /* the text file type. */ +static const char *default_type = APPLICATION_OCTET_STREAM; + + +/* + * Determins the format of the file "inputf". The name + * of the file format (or NULL on error) is returned. + */ +static const char *magic_look(char *inbuff, int numread) +{ + int i, j; + + for (i=0; i= magic[i].len) + { + for (j=0; j resFile; + NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true, + getter_AddRefs(resFile)); + if (!resFile) + return errFileOpen; + + FSRef ref; + nsCOMPtr macFile = do_QueryInterface(resFile); + if (NS_FAILED(macFile->GetFSRef(&ref))) + return errFileOpen; + + HFSUniStr255 forkName; + ::FSGetDataForkName(&forkName); + retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &fileId); + if (retval != noErr) + return retval; + + p_ap_encode_obj->fileId = fileId; + + + if (!p_ap_encode_obj->text_file_type) + { + /* + ** do a smart check for the file type. + */ + in_count = 0; + retval = ::FSReadFork(fileId, fsFromStart, 0, 256, rd_buff, &in_count); + magic_type = magic_look(rd_buff, in_count); + + /* don't forget to rewind the index to start point. */ + ::FSSetForkPosition(fileId, fsFromStart, 0); + /* and reset retVal just in case... */ + if (retval == eofErr) + retval = noErr; + } + else + { + magic_type = text_type; /* we already know it is a text type. */ + } + + /* + ** the data portion header information. + */ + nsAutoCString leafName; + resFile->GetNativeLeafName(leafName); + PR_snprintf(rd_buff, sizeof(rd_buff), + "Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\"" CRLF CRLF, + magic_type, + leafName.get(), + leafName.get()); + + status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff)); + if (status != noErr) + return status; + } + + while (retval == noErr) + { + if (BUFF_LEFT(p_ap_encode_obj) < 400) + break; + + in_count = 0; + retval = ::FSReadFork(p_ap_encode_obj->fileId, fsAtMark, 0, 256, rd_buff, &in_count); + if (in_count) + { +#if 0 +/* replace(rd_buff, in_count, '\r', '\n'); */ +#endif +/* ** may be need to do character set conversion here for localization. ** */ + status = to64(p_ap_encode_obj, + rd_buff, + in_count); + if (status != noErr) + return status; + } + } + + if (retval == eofErr) + { + ::FSCloseFork(p_ap_encode_obj->fileId); + p_ap_encode_obj->fileId = 0; + + status = finish64(p_ap_encode_obj); + if (status != noErr) + return status; + + /* write out the boundary */ + + PR_snprintf(rd_buff, sizeof(rd_buff), + CRLF "--%s--" CRLF CRLF, + p_ap_encode_obj->boundary); + + status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff)); + + if (status == noErr) + status = errDone; + } + return status; +} + +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* +** convert the stream in the inbuff to 64 format and put it in the out buff. +** To make the life easier, the caller will responcable of the cheking of the outbuff's bundary. +*/ +static int +to64(appledouble_encode_object* p_ap_encode_obj, + char *p, + int in_size) +{ + int status; + int c1, c2, c3, ct; + unsigned char *inbuff = (unsigned char*)p; + + ct = p_ap_encode_obj->ct; /* the char count left last time. */ + + /* + ** resume the left state of the last conversion. + */ + switch (p_ap_encode_obj->state64) + { + case 0: + p_ap_encode_obj->c1 = c1 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 1; + return noErr; + } + p_ap_encode_obj->c2 = c2 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 2; + return noErr; + } + c3 = *inbuff ++; --in_size; + break; + case 1: + c1 = p_ap_encode_obj->c1; + p_ap_encode_obj->c2 = c2 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 2; + return noErr; + } + c3 = *inbuff ++; --in_size; + break; + case 2: + c1 = p_ap_encode_obj->c1; + c2 = p_ap_encode_obj->c2; + c3 = *inbuff ++; --in_size; + break; + } + + while (in_size >= 0) + { + status = output64chunk(p_ap_encode_obj, + c1, + c2, + c3, + 0); + if (status != noErr) + return status; + + ct += 4; + if (ct > 71) + { + status = write_stream(p_ap_encode_obj, + CRLF, + 2); + if (status != noErr) + return status; + + ct = 0; + } + + if (in_size <= 0) + { + p_ap_encode_obj->state64 = 0; + break; + } + + c1 = (int)*inbuff++; + if (--in_size <= 0) + { + p_ap_encode_obj->c1 = c1; + p_ap_encode_obj->state64 = 1; + break; + } + c2 = *inbuff++; + if (--in_size <= 0) + { + p_ap_encode_obj->c1 = c1; + p_ap_encode_obj->c2 = c2; + p_ap_encode_obj->state64 = 2; + break; + } + c3 = *inbuff++; + in_size--; + } + p_ap_encode_obj->ct = ct; + return status; +} + +/* +** clear the left base64 encodes. +*/ +static int +finish64(appledouble_encode_object* p_ap_encode_obj) +{ + int status; + + switch (p_ap_encode_obj->state64) + { + case 0: + break; + case 1: + status = output64chunk(p_ap_encode_obj, + p_ap_encode_obj->c1, + 0, + 0, + 2); + break; + case 2: + status = output64chunk(p_ap_encode_obj, + p_ap_encode_obj->c1, + p_ap_encode_obj->c2, + 0, + 1); + break; + } + status = write_stream(p_ap_encode_obj, CRLF, 2); + p_ap_encode_obj->state64 = 0; + p_ap_encode_obj->ct = 0; + return status; +} + +static int output64chunk( + appledouble_encode_object* p_ap_encode_obj, + int c1, int c2, int c3, int pads) +{ + char tmpstr[32]; + char *p = tmpstr; + + *p++ = basis_64[c1>>2]; + *p++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)]; + if (pads == 2) + { + *p++ = '='; + *p++ = '='; + } + else if (pads) + { + *p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; + *p++ = '='; + } + else + { + *p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; + *p++ = basis_64[c3 & 0x3F]; + } + return write_stream(p_ap_encode_obj, (const char*) tmpstr, p-tmpstr); +} diff --git a/mailnews/import/build/moz.build b/mailnews/import/build/moz.build index 58814a6940..e8ac0751f5 100644 --- a/mailnews/import/build/moz.build +++ b/mailnews/import/build/moz.build @@ -35,6 +35,13 @@ LOCAL_INCLUDES += [ '../vcard/src', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '../applemail/src', + ] + OS_LIBS += CONFIG['TK_LIBS'] + OS_LIBS += ['-framework Cocoa'] + if CONFIG['OS_ARCH'] == 'WINNT': LOCAL_INCLUDES += [ ] diff --git a/media/libcubeb/src/cubeb_osx_run_loop.c b/media/libcubeb/src/cubeb_osx_run_loop.c new file mode 100644 index 0000000000..0ba9536560 --- /dev/null +++ b/media/libcubeb/src/cubeb_osx_run_loop.c @@ -0,0 +1,11 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "OSXRunLoopSingleton.h" + +void cubeb_set_coreaudio_notification_runloop() +{ + mozilla_set_coreaudio_notification_runloop_if_needed(); +} diff --git a/media/libcubeb/src/cubeb_osx_run_loop.h b/media/libcubeb/src/cubeb_osx_run_loop.h new file mode 100644 index 0000000000..78cd68d09b --- /dev/null +++ b/media/libcubeb/src/cubeb_osx_run_loop.h @@ -0,0 +1,22 @@ +/* + * Copyright © 2014 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ + +/* On OSX 10.6 and after, the notification callbacks from the audio hardware are + * called on the main thread. Setting the kAudioHardwarePropertyRunLoop property + * to null tells the OSX to use a separate thread for that. + * + * This has to be called only once per process, so it is in a separate header + * for easy integration in other code bases. */ +#if defined(__cplusplus) +extern "C" { +#endif + +void cubeb_set_coreaudio_notification_runloop(); + +#if defined(__cplusplus) +} +#endif diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build index c21cc873db..65aaf7256a 100644 --- a/media/libcubeb/src/moz.build +++ b/media/libcubeb/src/moz.build @@ -55,6 +55,10 @@ if CONFIG['OS_TARGET'] == 'Darwin': 'cubeb_audiounit.cpp', 'cubeb_resampler.cpp' ] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'cubeb_osx_run_loop.c', + ] DEFINES['USE_AUDIOUNIT'] = True if CONFIG['OS_TARGET'] == 'WINNT': diff --git a/netwerk/base/NetworkInfoServiceCocoa.cpp b/netwerk/base/NetworkInfoServiceCocoa.cpp new file mode 100644 index 0000000000..cdfa8e5c97 --- /dev/null +++ b/netwerk/base/NetworkInfoServiceCocoa.cpp @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mozilla/DebugOnly.h" +#include "mozilla/ScopeExit.h" + +#include "NetworkInfoServiceImpl.h" + +namespace mozilla { +namespace net { + +static nsresult +ListInterfaceAddresses(int aFd, const char* aIface, AddrMapType& aAddrMap); + +nsresult +DoListAddresses(AddrMapType& aAddrMap) +{ + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return NS_ERROR_FAILURE; + } + + auto autoCloseSocket = MakeScopeExit([&] { + close(fd); + }); + + struct ifconf ifconf; + /* 16k of space should be enough to list all interfaces. Worst case, if it's + * not then we will error out and fail to list addresses. This should only + * happen on pathological machines with way too many interfaces. + */ + char buf[16384]; + + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf = buf; + if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) { + return NS_ERROR_FAILURE; + } + + struct ifreq* ifreq = ifconf.ifc_req; + int i = 0; + while (i < ifconf.ifc_len) { + size_t len = IFNAMSIZ + ifreq->ifr_addr.sa_len; + + DebugOnly rv = + ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed"); + + ifreq = (struct ifreq*) ((char*)ifreq + len); + i += len; + } + + autoCloseSocket.release(); + return NS_OK; +} + +static nsresult +ListInterfaceAddresses(int aFd, const char* aInterface, AddrMapType& aAddrMap) +{ + struct ifreq ifreq; + memset(&ifreq, 0, sizeof(struct ifreq)); + strncpy(ifreq.ifr_name, aInterface, IFNAMSIZ - 1); + if (ioctl(aFd, SIOCGIFADDR, &ifreq) != 0) { + return NS_ERROR_FAILURE; + } + + char host[128]; + int family; + switch(family=ifreq.ifr_addr.sa_family) { + case AF_INET: + case AF_INET6: + getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), 0, 0, NI_NUMERICHOST); + break; + case AF_UNSPEC: + return NS_OK; + default: + // Unknown family. + return NS_OK; + } + + nsCString ifaceStr; + ifaceStr.AssignASCII(aInterface); + + nsCString addrStr; + addrStr.AssignASCII(host); + + aAddrMap.Put(ifaceStr, addrStr); + + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 3ec17b2b2a..1659299f7b 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -257,6 +257,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'nsURLHelperWin.cpp', 'ShutdownLayer.cpp', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'nsURLHelperOSX.cpp', + ] else: SOURCES += [ 'nsURLHelperUnix.cpp', @@ -268,6 +272,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'NetworkInfoServiceWindows.cpp', 'nsNetworkInfoService.cpp', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'NetworkInfoServiceCocoa.cpp', + 'nsNetworkInfoService.cpp', + ] elif CONFIG['OS_ARCH'] == 'Linux': SOURCES += [ 'NetworkInfoServiceLinux.cpp', diff --git a/netwerk/base/nsURLHelperOSX.cpp b/netwerk/base/nsURLHelperOSX.cpp new file mode 100644 index 0000000000..bcc0b257fb --- /dev/null +++ b/netwerk/base/nsURLHelperOSX.cpp @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Mac OS X-specific local file uri parsing */ +#include "nsURLHelper.h" +#include "nsEscape.h" +#include "nsIFile.h" +#include "nsTArray.h" +#include "nsReadableUtils.h" +#include + +static nsTArray *gVolumeList = nullptr; + +static bool pathBeginsWithVolName(const nsACString& path, nsACString& firstPathComponent) +{ + // Return whether the 1st path component in path (escaped) is equal to the name + // of a mounted volume. Return the 1st path component (unescaped) in any case. + // This needs to be done as quickly as possible, so we cache a list of volume names. + // XXX Register an event handler to detect drives being mounted/unmounted? + + if (!gVolumeList) { + gVolumeList = new nsTArray; + if (!gVolumeList) { + return false; // out of memory + } + } + + // Cache a list of volume names + if (!gVolumeList->Length()) { + OSErr err; + ItemCount volumeIndex = 1; + + do { + HFSUniStr255 volName; + FSRef rootDirectory; + err = ::FSGetVolumeInfo(0, volumeIndex, nullptr, kFSVolInfoNone, nullptr, + &volName, &rootDirectory); + if (err == noErr) { + NS_ConvertUTF16toUTF8 volNameStr(Substring((char16_t *)volName.unicode, + (char16_t *)volName.unicode + volName.length)); + gVolumeList->AppendElement(volNameStr); + volumeIndex++; + } + } while (err == noErr); + } + + // Extract the first component of the path + nsACString::const_iterator start; + path.BeginReading(start); + start.advance(1); // path begins with '/' + nsACString::const_iterator directory_end; + path.EndReading(directory_end); + nsACString::const_iterator component_end(start); + FindCharInReadable('/', component_end, directory_end); + + nsAutoCString flatComponent((Substring(start, component_end))); + NS_UnescapeURL(flatComponent); + int32_t foundIndex = gVolumeList->IndexOf(flatComponent); + firstPathComponent = flatComponent; + return (foundIndex != -1); +} + +void +net_ShutdownURLHelperOSX() +{ + delete gVolumeList; + gVolumeList = nullptr; +} + +static nsresult convertHFSPathtoPOSIX(const nsACString& hfsPath, nsACString& posixPath) +{ + // Use CFURL to do the conversion. We don't want to do this by simply + // using SwapSlashColon - we need the charset mapped from MacRoman + // to UTF-8, and we need "/Volumes" (or whatever - Apple says this is subject to change) + // prepended if the path is not on the boot drive. + + CFStringRef pathStrRef = CFStringCreateWithCString(nullptr, + PromiseFlatCString(hfsPath).get(), + kCFStringEncodingMacRoman); + if (!pathStrRef) + return NS_ERROR_FAILURE; + + nsresult rv = NS_ERROR_FAILURE; + CFURLRef urlRef = CFURLCreateWithFileSystemPath(nullptr, + pathStrRef, kCFURLHFSPathStyle, true); + if (urlRef) { + UInt8 pathBuf[PATH_MAX]; + if (CFURLGetFileSystemRepresentation(urlRef, true, pathBuf, sizeof(pathBuf))) { + posixPath = (char *)pathBuf; + rv = NS_OK; + } + } + CFRelease(pathStrRef); + if (urlRef) + CFRelease(urlRef); + return rv; +} + +static void SwapSlashColon(char *s) +{ + while (*s) { + if (*s == '/') + *s = ':'; + else if (*s == ':') + *s = '/'; + s++; + } +} + +nsresult +net_GetURLSpecFromActualFile(nsIFile *aFile, nsACString &result) +{ + // NOTE: This is identical to the implementation in nsURLHelperUnix.cpp + + nsresult rv; + nsAutoCString ePath; + + // construct URL spec from native file path + rv = aFile->GetNativePath(ePath); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString escPath; + NS_NAMED_LITERAL_CSTRING(prefix, "file://"); + + // Escape the path with the directory mask + if (NS_EscapeURL(ePath.get(), ePath.Length(), esc_Directory+esc_Forced, escPath)) + escPath.Insert(prefix, 0); + else + escPath.Assign(prefix + ePath); + + // esc_Directory does not escape the semicolons, so if a filename + // contains semicolons we need to manually escape them. + // This replacement should be removed in bug #473280 + escPath.ReplaceSubstring(";", "%3b"); + + result = escPath; + return NS_OK; +} + +nsresult +net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result) +{ + // NOTE: See also the implementation in nsURLHelperUnix.cpp + // This matches it except for the HFS path handling. + + nsresult rv; + + nsCOMPtr localFile; + rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localFile)); + if (NS_FAILED(rv)) + return rv; + + nsAutoCString directory, fileBaseName, fileExtension, path; + bool bHFSPath = false; + + rv = net_ParseFileURL(aURL, directory, fileBaseName, fileExtension); + if (NS_FAILED(rv)) + return rv; + + if (!directory.IsEmpty()) { + NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path); + + // The canonical form of file URLs on OSX use POSIX paths: + // file:///path-name. + // But, we still encounter file URLs that use HFS paths: + // file:///volume-name/path-name + // Determine that here and normalize HFS paths to POSIX. + nsAutoCString possibleVolName; + if (pathBeginsWithVolName(directory, possibleVolName)) { + // Though we know it begins with a volume name, it could still + // be a valid POSIX path if the boot drive is named "Mac HD" + // and there is a directory "Mac HD" at its root. If such a + // directory doesn't exist, we'll assume this is an HFS path. + FSRef testRef; + possibleVolName.Insert("/", 0); + if (::FSPathMakeRef((UInt8*)possibleVolName.get(), &testRef, nullptr) != noErr) + bHFSPath = true; + } + + if (bHFSPath) { + // "%2F"s need to become slashes, while all other slashes need to + // become colons. If we start out by changing "%2F"s to colons, we + // can reply on SwapSlashColon() to do what we need + path.ReplaceSubstring("%2F", ":"); + path.Cut(0, 1); // directory begins with '/' + SwapSlashColon((char *)path.get()); + // At this point, path is an HFS path made using the same + // algorithm as nsURLHelperMac. We'll convert to POSIX below. + } + } + if (!fileBaseName.IsEmpty()) + NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path); + if (!fileExtension.IsEmpty()) { + path += '.'; + NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path); + } + + NS_UnescapeURL(path); + if (path.Length() != strlen(path.get())) + return NS_ERROR_FILE_INVALID_PATH; + + if (bHFSPath) + convertHFSPathtoPOSIX(path, path); + + // assuming path is encoded in the native charset + rv = localFile->InitWithNativePath(path); + if (NS_FAILED(rv)) + return rv; + + localFile.forget(result); + return NS_OK; +} diff --git a/netwerk/build/moz.build b/netwerk/build/moz.build index 7c8416b9ac..ebafda48bb 100644 --- a/netwerk/build/moz.build +++ b/netwerk/build/moz.build @@ -36,7 +36,12 @@ if CONFIG['OS_ARCH'] == 'WINNT': '/netwerk/system/win32', ] -if CONFIG['OS_ARCH'] == 'Linux': +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LOCAL_INCLUDES += [ + '/netwerk/system/mac', + ] + +elif CONFIG['OS_ARCH'] == 'Linux': LOCAL_INCLUDES += [ '/netwerk/system/linux', ] diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp new file mode 100644 index 0000000000..72b5577749 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp @@ -0,0 +1,779 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MDNSResponderOperator.h" +#include "MDNSResponderReply.h" +#include "mozilla/EndianUtils.h" +#include "mozilla/Logging.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Unused.h" +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsDNSServiceInfo.h" +#include "nsHashPropertyBag.h" +#include "nsIProperty.h" +#include "nsISimpleEnumerator.h" +#include "nsIVariant.h" +#include "nsServiceManagerUtils.h" +#include "nsNetAddr.h" +#include "nsNetCID.h" +#include "nsSocketTransportService2.h" +#include "nsThreadUtils.h" +#include "nsXPCOMCID.h" +#include "private/pprio.h" + +#include "nsASocketHandler.h" + +namespace mozilla { +namespace net { + +static LazyLogModule gMDNSLog("MDNSResponderOperator"); +#undef LOG_I +#define LOG_I(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) +#undef LOG_E +#define LOG_E(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Error, (__VA_ARGS__)) + +class MDNSResponderOperator::ServiceWatcher final + : public nsASocketHandler +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + + // nsASocketHandler methods + virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags) override + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + MOZ_ASSERT(fd == mFD); + + if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL)) { + LOG_E("error polling on listening socket (%p)", fd); + mCondition = NS_ERROR_UNEXPECTED; + } + + if (!(outFlags & PR_POLL_READ)) { + return; + } + + DNSServiceProcessResult(mService); + } + + virtual void OnSocketDetached(PRFileDesc *fd) override + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + MOZ_ASSERT(mThread); + MOZ_ASSERT(fd == mFD); + + if (!mFD) { + return; + } + + // Bug 1175387: do not double close the handle here. + PR_ChangeFileDescNativeHandle(mFD, -1); + PR_Close(mFD); + mFD = nullptr; + + mThread->Dispatch(NewRunnableMethod(this, &ServiceWatcher::Deallocate), + NS_DISPATCH_NORMAL); + } + + virtual void IsLocal(bool *aIsLocal) override { *aIsLocal = true; } + + virtual void KeepWhenOffline(bool *aKeepWhenOffline) override + { + *aKeepWhenOffline = true; + } + + virtual uint64_t ByteCountSent() override { return 0; } + virtual uint64_t ByteCountReceived() override { return 0; } + + explicit ServiceWatcher(DNSServiceRef aService, + MDNSResponderOperator* aOperator) + : mThread(nullptr) + , mSts(nullptr) + , mOperatorHolder(aOperator) + , mService(aService) + , mFD(nullptr) + , mAttached(false) + { + if (!gSocketTransportService) + { + nsCOMPtr sts = + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); + } + } + + nsresult Init() + { + MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); + mThread = NS_GetCurrentThread(); + + if (!mService) { + return NS_OK; + } + + if (!gSocketTransportService) { + return NS_ERROR_FAILURE; + } + mSts = gSocketTransportService; + + int osfd = DNSServiceRefSockFD(mService); + if (osfd == -1) { + return NS_ERROR_FAILURE; + } + + mFD = PR_ImportFile(osfd); + return PostEvent(&ServiceWatcher::OnMsgAttach); + } + + void Close() + { + MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); + + if (!gSocketTransportService) { + Deallocate(); + return; + } + + PostEvent(&ServiceWatcher::OnMsgClose); + } + +private: + ~ServiceWatcher() = default; + + void Deallocate() + { + if (mService) { + DNSServiceRefDeallocate(mService); + mService = nullptr; + } + mOperatorHolder = nullptr; + } + + nsresult PostEvent(void(ServiceWatcher::*func)(void)) + { + return gSocketTransportService->Dispatch(NewRunnableMethod(this, func), + NS_DISPATCH_NORMAL); + } + + void OnMsgClose() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + if (NS_FAILED(mCondition)) { + return; + } + + // tear down socket. this signals the STS to detach our socket handler. + mCondition = NS_BINDING_ABORTED; + + // if we are attached, then socket transport service will call our + // OnSocketDetached method automatically. Otherwise, we have to call it + // (and thus close the socket) manually. + if (!mAttached) { + OnSocketDetached(mFD); + } + } + + void OnMsgAttach() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + if (NS_FAILED(mCondition)) { + return; + } + + mCondition = TryAttach(); + + // if we hit an error while trying to attach then bail... + if (NS_FAILED(mCondition)) { + NS_ASSERTION(!mAttached, "should not be attached already"); + OnSocketDetached(mFD); + } + + } + + nsresult TryAttach() + { + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + nsresult rv; + + if (!gSocketTransportService) { + return NS_ERROR_FAILURE; + } + + // + // find out if it is going to be ok to attach another socket to the STS. + // if not then we have to wait for the STS to tell us that it is ok. + // the notification is asynchronous, which means that when we could be + // in a race to call AttachSocket once notified. for this reason, when + // we get notified, we just re-enter this function. as a result, we are + // sure to ask again before calling AttachSocket. in this way we deal + // with the race condition. though it isn't the most elegant solution, + // it is far simpler than trying to build a system that would guarantee + // FIFO ordering (which wouldn't even be that valuable IMO). see bug + // 194402 for more info. + // + if (!gSocketTransportService->CanAttachSocket()) { + nsCOMPtr event = + NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach); + + nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); + if (NS_FAILED(rv)) { + return rv; + } + } + + // + // ok, we can now attach our socket to the STS for polling + // + rv = gSocketTransportService->AttachSocket(mFD, this); + if (NS_FAILED(rv)) { + return rv; + } + + mAttached = true; + + // + // now, configure our poll flags for listening... + // + mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT); + + return NS_OK; + } + + nsCOMPtr mThread; + RefPtr mSts; + RefPtr mOperatorHolder; + DNSServiceRef mService; + PRFileDesc* mFD; + bool mAttached; +}; + +NS_IMPL_ISUPPORTS(MDNSResponderOperator::ServiceWatcher, nsISupports) + +MDNSResponderOperator::MDNSResponderOperator() + : mService(nullptr) + , mWatcher(nullptr) + , mThread(NS_GetCurrentThread()) + , mIsCancelled(false) +{ +} + +MDNSResponderOperator::~MDNSResponderOperator() +{ + Stop(); +} + +nsresult +MDNSResponderOperator::Start() +{ + if (mIsCancelled) { + return NS_OK; + } + + if (IsServing()) { + Stop(); + } + + return NS_OK; +} + +nsresult +MDNSResponderOperator::Stop() +{ + return ResetService(nullptr); +} + +nsresult +MDNSResponderOperator::ResetService(DNSServiceRef aService) +{ + nsresult rv; + + if (aService != mService) { + if (mWatcher) { + mWatcher->Close(); + mWatcher = nullptr; + } + + if (aService) { + RefPtr watcher = new ServiceWatcher(aService, this); + if (NS_WARN_IF(NS_FAILED(rv = watcher->Init()))) { + return rv; + } + mWatcher = watcher; + } + + mService = aService; + } + return NS_OK; +} + +BrowseOperator::BrowseOperator(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener) + : MDNSResponderOperator() + , mServiceType(aServiceType) + , mListener(aListener) +{ +} + +nsresult +BrowseOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = DNSServiceBrowse(&service, + 0, + kDNSServiceInterfaceIndexAny, + mServiceType.get(), + nullptr, + &BrowseReplyRunnable::Reply, + this); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, "DNSServiceBrowse fail"); + + if (mListener) { + if (kDNSServiceErr_NoError == err) { + mListener->OnDiscoveryStarted(mServiceType); + } else { + mListener->OnStartDiscoveryFailed(mServiceType, err); + } + } + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +nsresult +BrowseOperator::Stop() +{ + bool isServing = IsServing(); + nsresult rv = MDNSResponderOperator::Stop(); + + if (isServing && mListener) { + if (NS_SUCCEEDED(rv)) { + mListener->OnDiscoveryStopped(mServiceType); + } else { + mListener->OnStopDiscoveryFailed(mServiceType, + static_cast(rv)); + } + } + + return rv; +} + +void +BrowseOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("BrowseOperator::Reply (%d)", aErrorCode); + if (mListener) { + mListener->OnStartDiscoveryFailed(mServiceType, aErrorCode); + } + return; + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(); + + if (NS_WARN_IF(!info)) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aServiceName)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aReplyDomain)))) { return; } + + if (aFlags & kDNSServiceFlagsAdd) { + mListener->OnServiceFound(info); + } else { + mListener->OnServiceLost(info); + } +} + +RegisterOperator::RegisterOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +RegisterOperator::Start() +{ + nsresult rv; + + rv = MDNSResponderOperator::Start(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + uint16_t port; + if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetPort(&port)))) { + return rv; + } + nsAutoCString type; + if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetServiceType(type)))) { + return rv; + } + + TXTRecordRef txtRecord; + char buf[TXT_BUFFER_SIZE] = { 0 }; + TXTRecordCreate(&txtRecord, TXT_BUFFER_SIZE, buf); + + nsCOMPtr attributes; + if (NS_FAILED(rv = mServiceInfo->GetAttributes(getter_AddRefs(attributes)))) { + LOG_I("register: no attributes"); + } else { + nsCOMPtr enumerator; + if (NS_WARN_IF(NS_FAILED(rv = + attributes->GetEnumerator(getter_AddRefs(enumerator))))) { + return rv; + } + + bool hasMoreElements; + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && + hasMoreElements) { + nsCOMPtr element; + MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element))); + nsCOMPtr property = do_QueryInterface(element); + MOZ_ASSERT(property); + + nsAutoString name; + nsCOMPtr value; + MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); + MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); + + nsAutoCString str; + if (NS_WARN_IF(NS_FAILED(value->GetAsACString(str)))) { + continue; + } + + TXTRecordSetValue(&txtRecord, + /* it's safe because key name is ASCII only. */ + NS_LossyConvertUTF16toASCII(name).get(), + str.Length(), + str.get()); + } + } + + nsAutoCString host; + nsAutoCString name; + nsAutoCString domain; + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceRegister(&service, + 0, + 0, + NS_SUCCEEDED(mServiceInfo->GetServiceName(name)) ? + name.get() : nullptr, + type.get(), + NS_SUCCEEDED(mServiceInfo->GetDomainName(domain)) ? + domain.get() : nullptr, + NS_SUCCEEDED(mServiceInfo->GetHost(host)) ? + host.get() : nullptr, + NativeEndian::swapToNetworkOrder(port), + TXTRecordGetLength(&txtRecord), + TXTRecordGetBytesPtr(&txtRecord), + &RegisterReplyRunnable::Reply, + this); + NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, + "DNSServiceRegister fail"); + + TXTRecordDeallocate(&txtRecord); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnRegistrationFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +nsresult +RegisterOperator::Stop() +{ + bool isServing = IsServing(); + nsresult rv = MDNSResponderOperator::Stop(); + + if (isServing && mListener) { + if (NS_SUCCEEDED(rv)) { + mListener->OnServiceUnregistered(mServiceInfo); + } else { + mListener->OnUnregistrationFailed(mServiceInfo, + static_cast(rv)); + } + } + + return rv; +} + +void +RegisterOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + if (kDNSServiceErr_NoError != aErrorCode) { + LOG_E("RegisterOperator::Reply (%d)", aErrorCode); + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aName)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aDomain)))) { return; } + + if (kDNSServiceErr_NoError == aErrorCode) { + if (aFlags & kDNSServiceFlagsAdd) { + mListener->OnServiceRegistered(info); + } else { + // If a successfully-registered name later suffers a name conflict + // or similar problem and has to be deregistered, the callback will + // be invoked with the kDNSServiceFlagsAdd flag not set. + LOG_E("RegisterOperator::Reply: deregister"); + if (NS_WARN_IF(NS_FAILED(Stop()))) { + return; + } + } + } else { + mListener->OnRegistrationFailed(info, aErrorCode); + } +} + +ResolveOperator::ResolveOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +ResolveOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + nsAutoCString name; + mServiceInfo->GetServiceName(name); + nsAutoCString type; + mServiceInfo->GetServiceType(type); + nsAutoCString domain; + mServiceInfo->GetDomainName(domain); + + LOG_I("Resolve: (%s), (%s), (%s)", name.get(), type.get(), domain.get()); + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceResolve(&service, + 0, + kDNSServiceInterfaceIndexAny, + name.get(), + type.get(), + domain.get(), + (DNSServiceResolveReply)&ResolveReplyRunnable::Reply, + this); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnResolveFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +void +ResolveOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + auto guard = MakeScopeExit([&] { + Unused << NS_WARN_IF(NS_FAILED(Stop())); + }); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("ResolveOperator::Reply (%d)", aErrorCode); + return; + } + + // Resolve TXT record + int count = TXTRecordGetCount(aTxtLen, aTxtRecord); + LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen); + nsCOMPtr attributes = new nsHashPropertyBag(); + if (NS_WARN_IF(!attributes)) { + return; + } + if (count) { + for (int i = 0; i < count; ++i) { + char key[TXT_BUFFER_SIZE] = { '\0' }; + uint8_t vSize = 0; + const void* value = nullptr; + if (kDNSServiceErr_NoError != + TXTRecordGetItemAtIndex(aTxtLen, + aTxtRecord, + i, + TXT_BUFFER_SIZE, + key, + &vSize, + &value)) { + break; + } + + nsAutoCString str(reinterpret_cast(value), vSize); + LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get()); + + if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString( + /* it's safe to convert because key name is ASCII only. */ + NS_ConvertASCIItoUTF16(key), + str)))) { + break; + } + } + } + + if (!mListener) { return; } + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { return; } + if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { return; } + + if (kDNSServiceErr_NoError == aErrorCode) { + GetAddrInfor(info); + } + else { + mListener->OnResolveFailed(info, aErrorCode); + Unused << NS_WARN_IF(NS_FAILED(Stop())); + } +} + +void +ResolveOperator::GetAddrInfor(nsIDNSServiceInfo* aServiceInfo) +{ + RefPtr getAddreOp = new GetAddrInfoOperator(aServiceInfo, + mListener); + Unused << NS_WARN_IF(NS_FAILED(getAddreOp->Start())); +} + +GetAddrInfoOperator::GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) + : MDNSResponderOperator() + , mServiceInfo(aServiceInfo) + , mListener(aListener) +{ +} + +nsresult +GetAddrInfoOperator::Start() +{ + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { + return rv; + } + + nsAutoCString host; + mServiceInfo->GetHost(host); + + LOG_I("GetAddrInfo: (%s)", host.get()); + + DNSServiceRef service = nullptr; + DNSServiceErrorType err = + DNSServiceGetAddrInfo(&service, + kDNSServiceFlagsForceMulticast, + kDNSServiceInterfaceIndexAny, + kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, + host.get(), + (DNSServiceGetAddrInfoReply)&GetAddrInfoReplyRunnable::Reply, + this); + + if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { + if (mListener) { + mListener->OnResolveFailed(mServiceInfo, err); + } + return NS_ERROR_FAILURE; + } + + return ResetService(service); +} + +void +GetAddrInfoOperator::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const NetAddr& aAddress, + uint32_t aTTL) +{ + MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); + + auto guard = MakeScopeExit([&] { + Unused << NS_WARN_IF(NS_FAILED(Stop())); + }); + + if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { + LOG_E("GetAddrInfoOperator::Reply (%d)", aErrorCode); + return; + } + + if (!mListener) { return; } + + NetAddr addr = aAddress; + nsCOMPtr address = new nsNetAddr(&addr); + nsCString addressStr; + if (NS_WARN_IF(NS_FAILED(address->GetAddress(addressStr)))) { return; } + + nsCOMPtr info = new nsDNSServiceInfo(mServiceInfo); + if (NS_WARN_IF(NS_FAILED(info->SetAddress(addressStr)))) { return; } + + /** + * |kDNSServiceFlagsMoreComing| means this callback will be one or more + * callback events later, so this instance should be kept alive until all + * follow-up events are processed. + */ + if (aFlags & kDNSServiceFlagsMoreComing) { + guard.release(); + } + + if (kDNSServiceErr_NoError == aErrorCode) { + mListener->OnServiceResolved(info); + } else { + mListener->OnResolveFailed(info, aErrorCode); + } +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h new file mode 100644 index 0000000000..a932baa7cc --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h +#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h + +#include "dns_sd.h" +#include "mozilla/Atomics.h" +#include "mozilla/RefPtr.h" +#include "nsCOMPtr.h" +#include "nsIDNSServiceDiscovery.h" +#include "nsIThread.h" +#include "nsString.h" + +namespace mozilla { +namespace net { + +class MDNSResponderOperator +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MDNSResponderOperator) + +public: + MDNSResponderOperator(); + + virtual nsresult Start(); + virtual nsresult Stop(); + void Cancel() { mIsCancelled = true; } + nsIThread* GetThread() const { return mThread; } + +protected: + virtual ~MDNSResponderOperator(); + + bool IsServing() const { return mService; } + nsresult ResetService(DNSServiceRef aService); + +private: + class ServiceWatcher; + + DNSServiceRef mService; + RefPtr mWatcher; + nsCOMPtr mThread; // remember caller thread for callback + Atomic mIsCancelled; +}; + +class BrowseOperator final : public MDNSResponderOperator +{ +public: + BrowseOperator(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener); + + nsresult Start() override; + nsresult Stop() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain); + +private: + ~BrowseOperator() = default; + + nsCString mServiceType; + nsCOMPtr mListener; +}; + +class RegisterOperator final : public MDNSResponderOperator +{ + enum { TXT_BUFFER_SIZE = 256 }; + +public: + RegisterOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener); + + nsresult Start() override; + nsresult Stop() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain); + +private: + ~RegisterOperator() = default; + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +class ResolveOperator final : public MDNSResponderOperator +{ + enum { TXT_BUFFER_SIZE = 256 }; + +public: + ResolveOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener); + + nsresult Start() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord); + +private: + ~ResolveOperator() = default; + void GetAddrInfor(nsIDNSServiceInfo* aServiceInfo); + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +union NetAddr; + +class GetAddrInfoOperator final : public MDNSResponderOperator +{ +public: + GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener); + + nsresult Start() override; + + void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const NetAddr& aAddress, + uint32_t aTTL); + +private: + ~GetAddrInfoOperator() = default; + + nsCOMPtr mServiceInfo; + nsCOMPtr mListener; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp new file mode 100644 index 0000000000..7aa5b3759a --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MDNSResponderReply.h" +#include "mozilla/EndianUtils.h" +#include "private/pprio.h" + +namespace mozilla { +namespace net { + +BrowseReplyRunnable::BrowseReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain, + BrowseOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mServiceName(aServiceName) + , mRegType(aRegType) + , mReplyDomain(aReplyDomain) + , mContext(aContext) +{ +} + +NS_IMETHODIMP +BrowseReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mServiceName, + mRegType, + mReplyDomain); + return NS_OK; +} + +void +BrowseReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aServiceName, + const char* aRegType, + const char* aReplyDomain, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + BrowseOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new BrowseReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aServiceName), + nsCString(aRegType), + nsCString(aReplyDomain), + obj), + NS_DISPATCH_NORMAL); +} + +RegisterReplyRunnable::RegisterReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& domain, + RegisterOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mErrorCode(aErrorCode) + , mName(aName) + , mRegType(aRegType) + , mDomain(domain) + , mContext(aContext) +{ +} + +NS_IMETHODIMP +RegisterReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + + mContext->Reply(mSdRef, + mFlags, + mErrorCode, + mName, + mRegType, + mDomain); + return NS_OK; +} + +void +RegisterReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const char* aName, + const char* aRegType, + const char* domain, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + RegisterOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new RegisterReplyRunnable(aSdRef, + aFlags, + aErrorCode, + nsCString(aName), + nsCString(aRegType), + nsCString(domain), + obj), + NS_DISPATCH_NORMAL); +} + +ResolveReplyRunnable::ResolveReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + ResolveOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mFullname(aFullName) + , mHosttarget(aHostTarget) + , mPort(aPort) + , mTxtLen(aTxtLen) + , mTxtRecord(new unsigned char[aTxtLen]) + , mContext(aContext) +{ + if (mTxtRecord) { + memcpy(mTxtRecord.get(), aTxtRecord, aTxtLen); + } +} + +ResolveReplyRunnable::~ResolveReplyRunnable() +{ +} + +NS_IMETHODIMP +ResolveReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mFullname, + mHosttarget, + mPort, + mTxtLen, + mTxtRecord.get()); + return NS_OK; +} + +void +ResolveReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aFullName, + const char* aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + ResolveOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + thread->Dispatch(new ResolveReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aFullName), + nsCString(aHostTarget), + NativeEndian::swapFromNetworkOrder(aPort), + aTxtLen, + aTxtRecord, + obj), + NS_DISPATCH_NORMAL); +} + +GetAddrInfoReplyRunnable::GetAddrInfoReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const mozilla::net::NetAddr& aAddress, + uint32_t aTTL, + GetAddrInfoOperator* aContext) + : mSdRef(aSdRef) + , mFlags(aFlags) + , mInterfaceIndex(aInterfaceIndex) + , mErrorCode(aErrorCode) + , mHostName(aHostName) + , mAddress(aAddress) + , mTTL(aTTL) + , mContext(aContext) +{ +} + +GetAddrInfoReplyRunnable::~GetAddrInfoReplyRunnable() +{ +} + +NS_IMETHODIMP +GetAddrInfoReplyRunnable::Run() +{ + MOZ_ASSERT(mContext); + mContext->Reply(mSdRef, + mFlags, + mInterfaceIndex, + mErrorCode, + mHostName, + mAddress, + mTTL); + return NS_OK; +} + +void +GetAddrInfoReplyRunnable::Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aHostName, + const struct sockaddr* aAddress, + uint32_t aTTL, + void* aContext) +{ + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + GetAddrInfoOperator* obj(reinterpret_cast(aContext)); + if (!obj) { + return; + } + + nsCOMPtr thread(obj->GetThread()); + if (!thread) { + return; + } + + NetAddr address; + address.raw.family = aAddress->sa_family; + + static_assert(sizeof(address.raw.data) >= sizeof(aAddress->sa_data), + "size of sockaddr.sa_data is too big"); + memcpy(&address.raw.data, aAddress->sa_data, sizeof(aAddress->sa_data)); + + thread->Dispatch(new GetAddrInfoReplyRunnable(aSdRef, + aFlags, + aInterfaceIndex, + aErrorCode, + nsCString(aHostName), + address, + aTTL, + obj), + NS_DISPATCH_NORMAL); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.h b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h new file mode 100644 index 0000000000..794a585f80 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h +#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h + +#include "dns_sd.h" +#include "MDNSResponderOperator.h" +#include "mozilla/UniquePtr.h" +#include "nsIThread.h" +#include "mozilla/net/DNS.h" +#include "mozilla/RefPtr.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace net { + +class BrowseReplyRunnable final : public Runnable +{ +public: + BrowseReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aServiceName, + const nsACString& aRegType, + const nsACString& aReplyDomain, + BrowseOperator* aContext); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aServiceName, + const char* aRegType, + const char* aReplyDomain, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mServiceName; + nsCString mRegType; + nsCString mReplyDomain; + RefPtr mContext; +}; + +class RegisterReplyRunnable final : public Runnable +{ +public: + RegisterReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const nsACString& aName, + const nsACString& aRegType, + const nsACString& aDomain, + RegisterOperator* aContext); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + DNSServiceErrorType aErrorCode, + const char* aName, + const char* aRegType, + const char* aDomain, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + DNSServiceErrorType mErrorCode; + nsCString mName; + nsCString mRegType; + nsCString mDomain; + RefPtr mContext; +}; + +class ResolveReplyRunnable final : public Runnable +{ +public: + ResolveReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aFullName, + const nsACString& aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + ResolveOperator* aContext); + ~ResolveReplyRunnable(); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aFullName, + const char* aHostTarget, + uint16_t aPort, + uint16_t aTxtLen, + const unsigned char* aTxtRecord, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mFullname; + nsCString mHosttarget; + uint16_t mPort; + uint16_t mTxtLen; + UniquePtr mTxtRecord; + RefPtr mContext; +}; + +class GetAddrInfoReplyRunnable final : public Runnable +{ +public: + GetAddrInfoReplyRunnable(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const nsACString& aHostName, + const mozilla::net::NetAddr& aAddress, + uint32_t aTTL, + GetAddrInfoOperator* aContext); + ~GetAddrInfoReplyRunnable(); + + NS_IMETHOD Run() override; + + static void Reply(DNSServiceRef aSdRef, + DNSServiceFlags aFlags, + uint32_t aInterfaceIndex, + DNSServiceErrorType aErrorCode, + const char* aHostName, + const struct sockaddr* aAddress, + uint32_t aTTL, + void* aContext); + +private: + DNSServiceRef mSdRef; + DNSServiceFlags mFlags; + uint32_t mInterfaceIndex; + DNSServiceErrorType mErrorCode; + nsCString mHostName; + mozilla::net::NetAddr mAddress; + uint32_t mTTL; + RefPtr mContext; +}; + +} // namespace net +} // namespace mozilla + + #endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h diff --git a/netwerk/dns/mdns/libmdns/moz.build b/netwerk/dns/mdns/libmdns/moz.build index 5a67c06118..23445756c6 100644 --- a/netwerk/dns/mdns/libmdns/moz.build +++ b/netwerk/dns/mdns/libmdns/moz.build @@ -3,20 +3,32 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -EXTRA_COMPONENTS += [ - 'nsDNSServiceDiscovery.js', - 'nsDNSServiceDiscovery.manifest', -] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'MDNSResponderOperator.cpp', + 'MDNSResponderReply.cpp', + 'nsDNSServiceDiscovery.cpp', + ] -EXTRA_JS_MODULES += [ - 'fallback/DataReader.jsm', - 'fallback/DataWriter.jsm', - 'fallback/DNSPacket.jsm', - 'fallback/DNSRecord.jsm', - 'fallback/DNSResourceRecord.jsm', - 'fallback/DNSTypes.jsm', - 'fallback/MulticastDNS.jsm', -] + LOCAL_INCLUDES += [ + '/netwerk/base', + ] + +else: + EXTRA_COMPONENTS += [ + 'nsDNSServiceDiscovery.js', + 'nsDNSServiceDiscovery.manifest', + ] + + EXTRA_JS_MODULES += [ + 'fallback/DataReader.jsm', + 'fallback/DataWriter.jsm', + 'fallback/DNSPacket.jsm', + 'fallback/DNSRecord.jsm', + 'fallback/DNSResourceRecord.jsm', + 'fallback/DNSTypes.jsm', + 'fallback/MulticastDNS.jsm', + ] SOURCES += [ 'nsDNSServiceInfo.cpp', diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp new file mode 100644 index 0000000000..cec8033d18 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsDNSServiceDiscovery.h" +#include "MDNSResponderOperator.h" +#include "nsICancelable.h" +#include "nsXULAppAPI.h" +#include "private/pprio.h" + +namespace mozilla { +namespace net { + +namespace { + +inline void +StartService() +{ + /*** STUB ***/ +} + +inline void +StopService() +{ + /*** STUB ***/ +} + +class ServiceCounter +{ +public: + static bool IsServiceRunning() + { + return !!sUseCount; + } + +private: + static uint32_t sUseCount; + +protected: + ServiceCounter() + { + MOZ_ASSERT(NS_IsMainThread()); + if (!sUseCount++) { + StartService(); + } + } + + virtual ~ServiceCounter() + { + MOZ_ASSERT(NS_IsMainThread()); + if (!--sUseCount) { + StopService(); + } + } +}; + +uint32_t ServiceCounter::sUseCount = 0; + +class DiscoveryRequest final : public nsICancelable + , private ServiceCounter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICANCELABLE + + explicit DiscoveryRequest(nsDNSServiceDiscovery* aService, + nsIDNSServiceDiscoveryListener* aListener); + +private: + virtual ~DiscoveryRequest() { Cancel(NS_OK); } + + RefPtr mService; + nsIDNSServiceDiscoveryListener* mListener; +}; + +NS_IMPL_ISUPPORTS(DiscoveryRequest, nsICancelable) + +DiscoveryRequest::DiscoveryRequest(nsDNSServiceDiscovery* aService, + nsIDNSServiceDiscoveryListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +DiscoveryRequest::Cancel(nsresult aReason) +{ + if (mService) { + mService->StopDiscovery(mListener); + } + + mService = nullptr; + return NS_OK; +} + +class RegisterRequest final : public nsICancelable + , private ServiceCounter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICANCELABLE + + explicit RegisterRequest(nsDNSServiceDiscovery* aService, + nsIDNSRegistrationListener* aListener); + +private: + virtual ~RegisterRequest() { Cancel(NS_OK); } + + RefPtr mService; + nsIDNSRegistrationListener* mListener; +}; + +NS_IMPL_ISUPPORTS(RegisterRequest, nsICancelable) + +RegisterRequest::RegisterRequest(nsDNSServiceDiscovery* aService, + nsIDNSRegistrationListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +RegisterRequest::Cancel(nsresult aReason) +{ + if (mService) { + mService->UnregisterService(mListener); + } + + mService = nullptr; + return NS_OK; +} + +} // namespace anonymous + +NS_IMPL_ISUPPORTS(nsDNSServiceDiscovery, nsIDNSServiceDiscovery) + +nsDNSServiceDiscovery::~nsDNSServiceDiscovery() +{ +} + +nsresult +nsDNSServiceDiscovery::Init() +{ + if (!XRE_IsParentProcess()) { + MOZ_ASSERT(false, "nsDNSServiceDiscovery can only be used in parent process"); + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::StartDiscovery(const nsACString& aServiceType, + nsIDNSServiceDiscoveryListener* aListener, + nsICancelable** aRetVal) +{ + MOZ_ASSERT(aRetVal); + + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = StopDiscovery(aListener)))) { + return rv; + } + + nsCOMPtr req = new DiscoveryRequest(this, aListener); + RefPtr browserOp = new BrowseOperator(aServiceType, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) { + return rv; + } + + mDiscoveryMap.Put(aListener, browserOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener) +{ + nsresult rv; + + RefPtr browserOp; + if (!mDiscoveryMap.Get(aListener, getter_AddRefs(browserOp))) { + return NS_OK; + } + + browserOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Stop()))) { + return rv; + } + + mDiscoveryMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::RegisterService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener, + nsICancelable** aRetVal) +{ + MOZ_ASSERT(aRetVal); + + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) { + return rv; + } + + nsCOMPtr req = new RegisterRequest(this, aListener); + RefPtr registerOp = new RegisterOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) { + return rv; + } + + mRegisterMap.Put(aListener, registerOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener) +{ + nsresult rv; + + RefPtr registerOp; + if (!mRegisterMap.Get(aListener, getter_AddRefs(registerOp))) { + return NS_OK; + } + + registerOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Stop()))) { + return rv; + } + + mRegisterMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) +{ + if (!ServiceCounter::IsServiceRunning()) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + + RefPtr resolveOp = new ResolveOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) { + return rv; + } + + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h new file mode 100644 index 0000000000..abe98f3574 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h +#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h + +#include "MDNSResponderOperator.h" +#include "nsIDNSServiceDiscovery.h" +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" +#include "nsRefPtrHashtable.h" + +namespace mozilla { +namespace net { + +class BrowseOperator; +class RegisterOperator; + +class nsDNSServiceDiscovery final : public nsIDNSServiceDiscovery +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSSERVICEDISCOVERY + + explicit nsDNSServiceDiscovery() = default; + + /* + ** The mDNS service is started on demand. If no one uses, mDNS service will not + ** start. Therefore, all operations before service started will fail + ** and get error code |kDNSServiceErr_ServiceNotRunning| defined in dns_sd.h. + **/ + nsresult Init(); + + nsresult StopDiscovery(nsIDNSServiceDiscoveryListener* aListener); + nsresult UnregisterService(nsIDNSRegistrationListener* aListener); + +private: + virtual ~nsDNSServiceDiscovery(); + + nsRefPtrHashtable mDiscoveryMap; + nsRefPtrHashtable mRegisterMap; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h diff --git a/netwerk/streamconv/converters/moz.build b/netwerk/streamconv/converters/moz.build index 546cfb9989..8630922404 100644 --- a/netwerk/streamconv/converters/moz.build +++ b/netwerk/streamconv/converters/moz.build @@ -11,7 +11,6 @@ XPIDL_MODULE = 'necko_http' SOURCES += [ 'mozTXTToHTMLConv.cpp', - 'nsBinHexDecoder.cpp', 'nsDirIndex.cpp', 'nsDirIndexParser.cpp', 'nsHTTPCompressConv.cpp', @@ -27,6 +26,11 @@ if 'ftp' in CONFIG['NECKO_PROTOCOLS']: 'ParseFTPList.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'cocoa': + SOURCES += [ + 'nsBinHexDecoder.cpp', + ] + FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ diff --git a/netwerk/system/mac/moz.build b/netwerk/system/mac/moz.build new file mode 100644 index 0000000000..f884a08b7c --- /dev/null +++ b/netwerk/system/mac/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'nsNetworkLinkService.mm', +] + +FINAL_LIBRARY = 'xul' + +if CONFIG['CLANG_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/netwerk/system/mac/nsNetworkLinkService.h b/netwerk/system/mac/nsNetworkLinkService.h new file mode 100644 index 0000000000..ee54622478 --- /dev/null +++ b/netwerk/system/mac/nsNetworkLinkService.h @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NSNETWORKLINKSERVICEMAC_H_ +#define NSNETWORKLINKSERVICEMAC_H_ + +#include "nsINetworkLinkService.h" +#include "nsIObserver.h" + +#include +#include + +class nsNetworkLinkService : public nsINetworkLinkService, + public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSINETWORKLINKSERVICE + NS_DECL_NSIOBSERVER + + nsNetworkLinkService(); + + nsresult Init(); + nsresult Shutdown(); + +protected: + virtual ~nsNetworkLinkService(); + +private: + bool mLinkUp; + bool mStatusKnown; + + // Toggles allowing the sending of network-changed event. + bool mAllowChangedEvent; + + SCNetworkReachabilityRef mReachability; + CFRunLoopRef mCFRunLoop; + CFRunLoopSourceRef mRunLoopSource; + SCDynamicStoreRef mStoreRef; + + void UpdateReachability(); + void SendEvent(bool aNetworkChanged); + static void ReachabilityChanged(SCNetworkReachabilityRef target, + SCNetworkConnectionFlags flags, + void *info); + static void IPConfigChanged(SCDynamicStoreRef store, + CFArrayRef changedKeys, + void *info); + void calculateNetworkId(void); + nsCString mNetworkId; +}; + +#endif /* NSNETWORKLINKSERVICEMAC_H_ */ diff --git a/netwerk/system/mac/nsNetworkLinkService.mm b/netwerk/system/mac/nsNetworkLinkService.mm new file mode 100644 index 0000000000..5b2d7575ac --- /dev/null +++ b/netwerk/system/mac/nsNetworkLinkService.mm @@ -0,0 +1,526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include "nsCOMPtr.h" +#include "nsIObserverService.h" +#include "nsServiceManagerUtils.h" +#include "nsString.h" +#include "nsCRT.h" +#include "mozilla/Logging.h" +#include "mozilla/Preferences.h" +#include "mozilla/SHA1.h" +#include "mozilla/Base64.h" +#include "nsNetworkLinkService.h" + +#import +#import + +#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed" + +using namespace mozilla; + +static LazyLogModule gNotifyAddrLog("nsNotifyAddr"); +#define LOG(args) MOZ_LOG(gNotifyAddrLog, mozilla::LogLevel::Debug, args) + +// If non-successful, extract the error code and return it. This +// error code dance is inspired by +// http://developer.apple.com/technotes/tn/tn1145.html +static OSStatus getErrorCodeBool(Boolean success) +{ + OSStatus err = noErr; + if (!success) { + int scErr = ::SCError(); + if (scErr == kSCStatusOK) { + scErr = kSCStatusFailed; + } + err = scErr; + } + return err; +} + +// If given a NULL pointer, return the error code. +static OSStatus getErrorCodePtr(const void *value) +{ + return getErrorCodeBool(value != NULL); +} + +// Convenience function to allow NULL input. +static void CFReleaseSafe(CFTypeRef cf) +{ + if (cf) { + // "If cf is NULL, this will cause a runtime error and your + // application will crash." / Apple docs + ::CFRelease(cf); + } +} + +NS_IMPL_ISUPPORTS(nsNetworkLinkService, + nsINetworkLinkService, + nsIObserver) + +nsNetworkLinkService::nsNetworkLinkService() + : mLinkUp(true) + , mStatusKnown(false) + , mAllowChangedEvent(true) + , mReachability(nullptr) + , mCFRunLoop(nullptr) + , mRunLoopSource(nullptr) + , mStoreRef(nullptr) +{ +} + +nsNetworkLinkService::~nsNetworkLinkService() = default; + +NS_IMETHODIMP +nsNetworkLinkService::GetIsLinkUp(bool *aIsUp) +{ + *aIsUp = mLinkUp; + return NS_OK; +} + +NS_IMETHODIMP +nsNetworkLinkService::GetLinkStatusKnown(bool *aIsUp) +{ + *aIsUp = mStatusKnown; + return NS_OK; +} + +NS_IMETHODIMP +nsNetworkLinkService::GetLinkType(uint32_t *aLinkType) +{ + NS_ENSURE_ARG_POINTER(aLinkType); + + // XXX This function has not yet been implemented for this platform + *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN; + return NS_OK; +} + +#ifndef SA_SIZE +#define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(uint32_t) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) ) +#endif + +static char *getMac(struct sockaddr_dl *sdl, char *buf, size_t bufsize) +{ + char *cp; + int n, p = 0; + + buf[0] = 0; + cp = (char *)LLADDR(sdl); + n = sdl->sdl_alen; + if (n > 0) { + while (--n >= 0) { + p += snprintf(&buf[p], bufsize - p, "%02x%s", + *cp++ & 0xff, n > 0 ? ":" : ""); + } + } + return buf; +} + +/* If the IP matches, get the MAC and return true */ +static bool matchIp(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr, + char *ip, char *buf, size_t bufsize) +{ + if (sdl->sdl_alen) { + if (!strcmp(inet_ntoa(addr->sin_addr), ip)) { + getMac(sdl, buf, bufsize); + return true; /* done! */ + } + } + return false; /* continue */ +} + +/* + * Scan for the 'IP' address in the ARP table and store the corresponding MAC + * address in 'mac'. The output buffer is 'maclen' bytes big. + * + * Returns 'true' if it found the IP and returns a MAC. + */ +static bool scanArp(char *ip, char *mac, size_t maclen) +{ + int mib[6]; + char *lim, *next; + int st; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + + size_t needed; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + return false; + } + if (needed == 0) { + // empty table + return false; + } + + UniquePtr buf(new char[needed]); + + for (;;) { + st = sysctl(mib, 6, &buf[0], &needed, NULL, 0); + if (st == 0 || errno != ENOMEM) { + break; + } + needed += needed / 8; + + auto tmp = MakeUnique(needed); + memcpy(&tmp[0], &buf[0], needed); + buf = Move(tmp); + } + if (st == -1) { + return false; + } + lim = &buf[needed]; + + struct rt_msghdr *rtm; + for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) { + rtm = reinterpret_cast(next); + struct sockaddr_inarp *sin2 = + reinterpret_cast(rtm + 1); + struct sockaddr_dl *sdl = + reinterpret_cast + ((char *)sin2 + SA_SIZE(sin2)); + if (matchIp(sdl, sin2, ip, mac, maclen)) { + return true; + } + } + + return false; +} + +static int routingTable(char *gw, size_t aGwLen) +{ + size_t needed; + int mib[6]; + struct rt_msghdr *rtm; + struct sockaddr *sa; + struct sockaddr_in *sockin; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + return 1; + } + + UniquePtr buf(new char[needed]); + + if (sysctl(mib, 6, &buf[0], &needed, NULL, 0) < 0) { + return 3; + } + + rtm = reinterpret_cast(&buf[0]); + sa = reinterpret_cast(rtm + 1); + sa = reinterpret_cast(SA_SIZE(sa) + (char *)sa); + sockin = reinterpret_cast(sa); + inet_ntop(AF_INET, &sockin->sin_addr.s_addr, gw, aGwLen-1); + + return 0; +} + +// +// Figure out the current "network identification" string. +// +// It detects the IP of the default gateway in the routing table, then the MAC +// address of that IP in the ARP table before it hashes that string (to avoid +// information leakage). +// +void nsNetworkLinkService::calculateNetworkId(void) +{ + bool found = false; + char hw[MAXHOSTNAMELEN]; + if (!routingTable(hw, sizeof(hw))) { + char mac[256]; // big enough for a printable MAC address + if (scanArp(hw, mac, sizeof(mac))) { + LOG(("networkid: MAC %s\n", hw)); + nsAutoCString mac(hw); + // This 'addition' could potentially be a + // fixed number from the profile or something. + nsAutoCString addition("local-rubbish"); + nsAutoCString output; + SHA1Sum sha1; + nsCString combined(mac + addition); + sha1.update(combined.get(), combined.Length()); + uint8_t digest[SHA1Sum::kHashSize]; + sha1.finish(digest); + nsCString newString(reinterpret_cast(digest), + SHA1Sum::kHashSize); + nsresult rv = Base64Encode(newString, output); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + LOG(("networkid: id %s\n", output.get())); + if (mNetworkId != output) { + // new id + mNetworkId = output; + } + else { + // same id + } + found = true; + } + } + if (!found) { + // no id + } +} + + +NS_IMETHODIMP +nsNetworkLinkService::Observe(nsISupports *subject, + const char *topic, + const char16_t *data) +{ + if (!strcmp(topic, "xpcom-shutdown")) { + Shutdown(); + } + + return NS_OK; +} + +/* static */ +void +nsNetworkLinkService::IPConfigChanged(SCDynamicStoreRef aStoreREf, + CFArrayRef aChangedKeys, + void *aInfo) +{ + nsNetworkLinkService *service = + static_cast(aInfo); + service->SendEvent(true); +} + +nsresult +nsNetworkLinkService::Init(void) +{ + nsresult rv; + + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = observerService->AddObserver(this, "xpcom-shutdown", false); + NS_ENSURE_SUCCESS(rv, rv); + + Preferences::AddBoolVarCache(&mAllowChangedEvent, + NETWORK_NOTIFY_CHANGED_PREF, true); + + // If the network reachability API can reach 0.0.0.0 without + // requiring a connection, there is a network interface available. + struct sockaddr_in addr; + bzero(&addr, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + mReachability = + ::SCNetworkReachabilityCreateWithAddress(NULL, + (struct sockaddr *)&addr); + if (!mReachability) { + return NS_ERROR_NOT_AVAILABLE; + } + + SCNetworkReachabilityContext context = {0, this, NULL, NULL, NULL}; + if (!::SCNetworkReachabilitySetCallback(mReachability, + ReachabilityChanged, + &context)) { + NS_WARNING("SCNetworkReachabilitySetCallback failed."); + ::CFRelease(mReachability); + mReachability = NULL; + return NS_ERROR_NOT_AVAILABLE; + } + + SCDynamicStoreContext storeContext = {0, this, NULL, NULL, NULL}; + mStoreRef = + ::SCDynamicStoreCreate(NULL, + CFSTR("AddIPAddressListChangeCallbackSCF"), + IPConfigChanged, &storeContext); + + CFStringRef patterns[2] = {NULL, NULL}; + OSStatus err = getErrorCodePtr(mStoreRef); + if (err == noErr) { + // This pattern is "State:/Network/Service/[^/]+/IPv4". + patterns[0] = + ::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv4); + err = getErrorCodePtr(patterns[0]); + if (err == noErr) { + // This pattern is "State:/Network/Service/[^/]+/IPv6". + patterns[1] = + ::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv6); + err = getErrorCodePtr(patterns[1]); + } + } + + CFArrayRef patternList = NULL; + // Create a pattern list containing just one pattern, + // then tell SCF that we want to watch changes in keys + // that match that pattern list, then create our run loop + // source. + if (err == noErr) { + patternList = ::CFArrayCreate(NULL, (const void **) patterns, + 2, &kCFTypeArrayCallBacks); + if (!patternList) { + err = -1; + } + } + if (err == noErr) { + err = + getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef, + NULL, + patternList)); + } + + if (err == noErr) { + mRunLoopSource = + ::SCDynamicStoreCreateRunLoopSource(NULL, mStoreRef, 0); + err = getErrorCodePtr(mRunLoopSource); + } + + CFReleaseSafe(patterns[0]); + CFReleaseSafe(patterns[1]); + CFReleaseSafe(patternList); + + if (err != noErr) { + CFReleaseSafe(mStoreRef); + return NS_ERROR_NOT_AVAILABLE; + } + + // Get the current run loop. This service is initialized at startup, + // so we shouldn't run in to any problems with modal dialog run loops. + mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop]; + if (!mCFRunLoop) { + NS_WARNING("Could not get current run loop."); + ::CFRelease(mReachability); + mReachability = NULL; + return NS_ERROR_NOT_AVAILABLE; + } + ::CFRetain(mCFRunLoop); + + ::CFRunLoopAddSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode); + + if (!::SCNetworkReachabilityScheduleWithRunLoop(mReachability, mCFRunLoop, + kCFRunLoopDefaultMode)) { + NS_WARNING("SCNetworkReachabilityScheduleWIthRunLoop failed."); + ::CFRelease(mReachability); + mReachability = NULL; + ::CFRelease(mCFRunLoop); + mCFRunLoop = NULL; + return NS_ERROR_NOT_AVAILABLE; + } + + UpdateReachability(); + + return NS_OK; +} + +nsresult +nsNetworkLinkService::Shutdown() +{ + if (!::SCNetworkReachabilityUnscheduleFromRunLoop(mReachability, + mCFRunLoop, + kCFRunLoopDefaultMode)) { + NS_WARNING("SCNetworkReachabilityUnscheduleFromRunLoop failed."); + } + + CFRunLoopRemoveSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode); + + ::CFRelease(mReachability); + mReachability = nullptr; + + ::CFRelease(mCFRunLoop); + mCFRunLoop = nullptr; + + ::CFRelease(mStoreRef); + mStoreRef = nullptr; + + ::CFRelease(mRunLoopSource); + mRunLoopSource = nullptr; + + return NS_OK; +} + +void +nsNetworkLinkService::UpdateReachability() +{ + if (!mReachability) { + return; + } + + SCNetworkConnectionFlags flags; + if (!::SCNetworkReachabilityGetFlags(mReachability, &flags)) { + mStatusKnown = false; + return; + } + + bool reachable = (flags & kSCNetworkFlagsReachable) != 0; + bool needsConnection = (flags & kSCNetworkFlagsConnectionRequired) != 0; + + mLinkUp = (reachable && !needsConnection); + mStatusKnown = true; +} + +void +nsNetworkLinkService::SendEvent(bool aNetworkChanged) +{ + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (!observerService) { + return; + } + + const char *event; + if (aNetworkChanged) { + if (!mAllowChangedEvent) { + return; + } + event = NS_NETWORK_LINK_DATA_CHANGED; + } else if (!mStatusKnown) { + event = NS_NETWORK_LINK_DATA_UNKNOWN; + } else { + event = mLinkUp ? NS_NETWORK_LINK_DATA_UP + : NS_NETWORK_LINK_DATA_DOWN; + } + LOG(("SendEvent: network is '%s'\n", event)); + + observerService->NotifyObservers(static_cast(this), + NS_NETWORK_LINK_TOPIC, + NS_ConvertASCIItoUTF16(event).get()); +} + +/* static */ +void +nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target, + SCNetworkConnectionFlags flags, + void *info) +{ + nsNetworkLinkService *service = + static_cast(info); + + service->UpdateReachability(); + service->SendEvent(false); + service->calculateNetworkId(); +} diff --git a/netwerk/system/moz.build b/netwerk/system/moz.build index a8034d7497..dcf7d6c3f1 100644 --- a/netwerk/system/moz.build +++ b/netwerk/system/moz.build @@ -5,5 +5,7 @@ if CONFIG['OS_ARCH'] == 'WINNT': DIRS += ['win32'] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DIRS += ['mac'] elif CONFIG['OS_ARCH'] == 'Linux': DIRS += ['linux'] diff --git a/toolkit/components/parentalcontrols/moz.build b/toolkit/components/parentalcontrols/moz.build index 6c8bd9a8ce..577162945b 100644 --- a/toolkit/components/parentalcontrols/moz.build +++ b/toolkit/components/parentalcontrols/moz.build @@ -10,6 +10,8 @@ XPIDL_MODULE = 'parentalcontrols' if not CONFIG['MOZ_DISABLE_PARENTAL_CONTROLS']: if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': SOURCES += ['nsParentalControlsServiceWin.cpp'] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + UNIFIED_SOURCES += ['nsParentalControlsServiceCocoa.mm'] else: SOURCES += ['nsParentalControlsServiceDefault.cpp'] diff --git a/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm new file mode 100644 index 0000000000..0eb0184001 --- /dev/null +++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceCocoa.mm @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsParentalControlsService.h" +#include "nsString.h" +#include "nsIFile.h" + +#import + +NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService) + +nsParentalControlsService::nsParentalControlsService() : + mEnabled(false) +{ + mEnabled = CFPreferencesAppValueIsForced(CFSTR("restrictWeb"), + CFSTR("com.apple.familycontrols.contentfilter")); +} + +nsParentalControlsService::~nsParentalControlsService() +{ +} + +NS_IMETHODIMP +nsParentalControlsService::GetParentalControlsEnabled(bool *aResult) +{ + *aResult = mEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::GetBlockFileDownloadsEnabled(bool *aResult) +{ + *aResult = false; + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::GetLoggingEnabled(bool *aResult) +{ + *aResult = false; + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::Log(int16_t aEntryType, + bool blocked, + nsIURI *aSource, + nsIFile *aTarget) +{ + // silently drop on the floor + return NS_OK; +} + +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverride(nsIURI *aTarget, + nsIInterfaceRequestor *aWindowContext, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::RequestURIOverrides(nsIArray *aTargets, + nsIInterfaceRequestor *aWindowContext, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsParentalControlsService::IsAllowed(int16_t aAction, + nsIURI *aUri, + bool *_retval) +{ + return NS_ERROR_NOT_AVAILABLE; +} + diff --git a/toolkit/components/startup/moz.build b/toolkit/components/startup/moz.build index 7ee23d9ce8..b12fe9a534 100644 --- a/toolkit/components/startup/moz.build +++ b/toolkit/components/startup/moz.build @@ -7,7 +7,7 @@ DIRS += ['public'] EXPORTS.mozilla += ['StartupTimeline.h'] -SOURCES += [ +UNIFIED_SOURCES += [ 'nsAppStartup.cpp', 'StartupTimeline.cpp', ] @@ -16,7 +16,9 @@ if CONFIG['MOZ_USERINFO']: if CONFIG['OS_ARCH'] == 'WINNT': # This file cannot be built in unified mode because of name clashes with Windows headers. SOURCES += ['nsUserInfoWin.cpp'] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + UNIFIED_SOURCES += ['nsUserInfoMac.mm'] else: - SOURCES += ['nsUserInfoUnix.cpp'] + UNIFIED_SOURCES += ['nsUserInfoUnix.cpp'] FINAL_LIBRARY = 'xul' diff --git a/toolkit/components/startup/nsUserInfoMac.h b/toolkit/components/startup/nsUserInfoMac.h new file mode 100644 index 0000000000..822e0edd5d --- /dev/null +++ b/toolkit/components/startup/nsUserInfoMac.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef __nsUserInfoMac_h +#define __nsUserInfoMac_h + +#include "nsIUserInfo.h" +#include "nsReadableUtils.h" + +class nsUserInfo: public nsIUserInfo +{ +public: + nsUserInfo(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIUSERINFO + + nsresult GetPrimaryEmailAddress(nsCString &aEmailAddress); + +protected: + virtual ~nsUserInfo() {} +}; + +#endif /* __nsUserInfo_h */ diff --git a/toolkit/components/startup/nsUserInfoMac.mm b/toolkit/components/startup/nsUserInfoMac.mm new file mode 100644 index 0000000000..1895cf1773 --- /dev/null +++ b/toolkit/components/startup/nsUserInfoMac.mm @@ -0,0 +1,84 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +#include "nsUserInfoMac.h" +#include "nsObjCExceptions.h" +#include "nsString.h" + +#import +#import + +NS_IMPL_ISUPPORTS(nsUserInfo, nsIUserInfo) + +nsUserInfo::nsUserInfo() {} + +NS_IMETHODIMP +nsUserInfo::GetFullname(char16_t **aFullname) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT + + NS_ConvertUTF8toUTF16 fullName([NSFullUserName() UTF8String]); + *aFullname = ToNewUnicode(fullName); + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT +} + +NS_IMETHODIMP +nsUserInfo::GetUsername(char **aUsername) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT + + nsAutoCString username([NSUserName() UTF8String]); + *aUsername = ToNewCString(username); + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT +} + +nsresult +nsUserInfo::GetPrimaryEmailAddress(nsCString &aEmailAddress) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT + + // Try to get this user's primary email from the system addressbook's "me card" + // (if they've filled it) + ABPerson *me = [[ABAddressBook sharedAddressBook] me]; + ABMultiValue *emailAddresses = [me valueForProperty:kABEmailProperty]; + if ([emailAddresses count] > 0) { + // get the index of the primary email, in case there are more than one + int primaryEmailIndex = [emailAddresses indexForIdentifier:[emailAddresses primaryIdentifier]]; + aEmailAddress.Assign([[emailAddresses valueAtIndex:primaryEmailIndex] UTF8String]); + return NS_OK; + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT +} + +NS_IMETHODIMP +nsUserInfo::GetEmailAddress(char **aEmailAddress) +{ + nsAutoCString email; + if (NS_SUCCEEDED(GetPrimaryEmailAddress(email))) + *aEmailAddress = ToNewCString(email); + return NS_OK; +} + +NS_IMETHODIMP +nsUserInfo::GetDomain(char **aDomain) +{ + nsAutoCString email; + if (NS_SUCCEEDED(GetPrimaryEmailAddress(email))) { + int32_t index = email.FindChar('@'); + if (index != -1) { + // chop off everything before, and including the '@' + *aDomain = ToNewCString(Substring(email, index + 1)); + } + } + return NS_OK; +} diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 81f07be661..c2f12b7763 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -12,8 +12,14 @@ def Libxul_defines(): @template def Libxul(name): - GeckoSharedLibrary(name, linkage=None) - SHARED_LIBRARY_NAME = 'xul' + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'): + # This is going to be a framework named "XUL", not an ordinary library named + # "libxul.dylib" + GeckoFramework(name, linkage=None) + SHARED_LIBRARY_NAME = 'XUL' + else: + GeckoSharedLibrary(name, linkage=None) + SHARED_LIBRARY_NAME = 'xul' DELAYLOAD_DLLS += [ 'comdlg32.dll', @@ -121,6 +127,9 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT'] or \ 'freetype', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + CXXFLAGS += CONFIG['TK_CFLAGS'] + if CONFIG['MOZ_WEBRTC']: if CONFIG['OS_TARGET'] == 'WINNT': OS_LIBS += [ @@ -134,6 +143,19 @@ if CONFIG['MOZ_WEBRTC']: 'wininet', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + OS_LIBS += [ + '-framework OpenGL', + '-framework SystemConfiguration', + '-framework AVFoundation', + '-framework CoreMedia', + '-framework IOKit', + '-F%s' % CONFIG['MACOS_PRIVATE_FRAMEWORKS_DIR'], + '-framework CoreUI', + '-framework CoreSymbolication', + 'cups', + ] + if CONFIG['MOZ_WMF']: OS_LIBS += [ 'mfuuid', @@ -191,6 +213,9 @@ if 'rtsp' in CONFIG['NECKO_PROTOCOLS']: OS_LIBS += CONFIG['ICONV_LIBS'] +if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'): + OS_LIBS += CONFIG['TK_LIBS'] + if CONFIG['MOZ_SNDIO']: OS_LIBS += [ 'sndio', @@ -276,11 +301,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': ] if CONFIG['COMPILE_ENVIRONMENT']: - full_libname = '%s%s%s' % ( - CONFIG['DLL_PREFIX'], - LIBRARY_NAME, - CONFIG['DLL_SUFFIX'] - ) + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'): + full_libname = SHARED_LIBRARY_NAME + else: + full_libname = '%s%s%s' % ( + CONFIG['DLL_PREFIX'], + LIBRARY_NAME, + CONFIG['DLL_SUFFIX'] + ) GENERATED_FILES += ['dependentlibs.list'] GENERATED_FILES['dependentlibs.list'].script = 'dependentlibs.py:gen_list' GENERATED_FILES['dependentlibs.list'].inputs = [ diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index e38b1b0b75..836fd66b36 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -94,7 +94,7 @@ EXTRA_PP_JS_MODULES += [ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'): DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1 -if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'): +if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'): DEFINES['HAVE_SHELL_SERVICE'] = 1 EXTRA_PP_JS_MODULES += [ diff --git a/toolkit/moz.build b/toolkit/moz.build index 9bf579bb26..9e05b2a4fb 100644 --- a/toolkit/moz.build +++ b/toolkit/moz.build @@ -39,5 +39,7 @@ DIRS += ['xre'] if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'): DIRS += ['system/unixproxy'] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DIRS += ['system/osxproxy'] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': DIRS += ['system/windowsproxy'] diff --git a/toolkit/moz.configure b/toolkit/moz.configure index e3d3eca63d..643b4fbe34 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -48,7 +48,7 @@ set_config('L10NBASEDIR', l10n_base) # reason. option('--enable-default-toolkit', nargs=1, choices=('cairo-windows', 'cairo-gtk2', 'cairo-gtk2-x11', 'cairo-gtk3', - 'cairo-uikit'), + 'cairo-cocoa', 'cairo-uikit'), help='Select default toolkit') @depends('--enable-default-toolkit', target) @@ -58,6 +58,8 @@ def toolkit(value, target): os = target.os if target.os == 'WINNT': platform_choices = ('cairo-windows',) + elif target.os == 'OSX': + platform_choices = ('cairo-cocoa',) elif target.os == 'iOS': platform_choices = ('cairo-uikit',) else: @@ -180,7 +182,7 @@ option(env='MOZ_INSTRUMENT_EVENT_LOOP', @depends('MOZ_INSTRUMENT_EVENT_LOOP', toolkit) def instrument_event_loop(value, toolkit): - if value or (toolkit in ('windows', 'gtk2', 'gtk3') and value.origin == 'default'): + if value or (toolkit in ('windows', 'gtk2', 'gtk3', 'cocoa') and value.origin == 'default'): return True set_config('MOZ_INSTRUMENT_EVENT_LOOP', instrument_event_loop) @@ -266,7 +268,7 @@ add_old_configure_assignment('FT2_CFLAGS', # ============================================================== @depends(toolkit) def applemedia(toolkit): - if toolkit in ('uikit'): + if toolkit in ('cocoa', 'uikit'): return True set_config('MOZ_APPLEMEDIA', applemedia) diff --git a/toolkit/mozapps/update/updater/Makefile.in b/toolkit/mozapps/update/updater/Makefile.in index c1cfcead7e..84a843d185 100644 --- a/toolkit/mozapps/update/updater/Makefile.in +++ b/toolkit/mozapps/update/updater/Makefile.in @@ -14,3 +14,16 @@ endif endif include $(topsrcdir)/config/rules.mk + +ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) +export:: + sed -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/bin/Info.plist +libs:: + $(NSINSTALL) -D $(DIST)/bin/updater.app + rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/updater.app + rsync -a -C $(DIST)/bin/Info.plist $(DIST)/bin/updater.app/Contents + sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \ + iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings + $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS + $(NSINSTALL) $(DIST)/bin/org.mozilla.updater $(DIST)/bin/updater.app/Contents/MacOS +endif diff --git a/toolkit/mozapps/update/updater/launchchild_osx.mm b/toolkit/mozapps/update/updater/launchchild_osx.mm new file mode 100644 index 0000000000..5a36ae6237 --- /dev/null +++ b/toolkit/mozapps/update/updater/launchchild_osx.mm @@ -0,0 +1,384 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include +#include +#include +#include +#include "readstrings.h" + +class MacAutoreleasePool { +public: + MacAutoreleasePool() + { + mPool = [[NSAutoreleasePool alloc] init]; + } + ~MacAutoreleasePool() + { + [mPool release]; + } + +private: + NSAutoreleasePool* mPool; +}; + +void LaunchChild(int argc, const char** argv) +{ + MacAutoreleasePool pool; + + @try { + NSString* launchPath = [NSString stringWithUTF8String:argv[0]]; + NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:argc - 1]; + for (int i = 1; i < argc; i++) { + [arguments addObject:[NSString stringWithUTF8String:argv[i]]]; + } + [NSTask launchedTaskWithLaunchPath:launchPath + arguments:arguments]; + } @catch (NSException* e) { + NSLog(@"%@: %@", e.name, e.reason); + } +} + +void +LaunchMacPostProcess(const char* aAppBundle) +{ + MacAutoreleasePool pool; + + // Launch helper to perform post processing for the update; this is the Mac + // analogue of LaunchWinPostProcess (PostUpdateWin). + NSString* iniPath = [NSString stringWithUTF8String:aAppBundle]; + iniPath = + [iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"]; + + NSFileManager* fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:iniPath]) { + // the file does not exist; there is nothing to run + return; + } + + int readResult; + char values[2][MAX_TEXT_LEN]; + readResult = ReadStrings([iniPath UTF8String], + "ExeRelPath\0ExeArg\0", + 2, + values, + "PostUpdateMac"); + if (readResult) { + return; + } + + NSString *exeRelPath = [NSString stringWithUTF8String:values[0]]; + NSString *exeArg = [NSString stringWithUTF8String:values[1]]; + if (!exeArg || !exeRelPath) { + return; + } + + // The path must not traverse directories and it must be a relative path. + if ([exeRelPath rangeOfString:@".."].location != NSNotFound || + [exeRelPath rangeOfString:@"./"].location != NSNotFound || + [exeRelPath rangeOfString:@"/"].location == 0) { + return; + } + + NSString* exeFullPath = [NSString stringWithUTF8String:aAppBundle]; + exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath]; + + char optVals[1][MAX_TEXT_LEN]; + readResult = ReadStrings([iniPath UTF8String], + "ExeAsync\0", + 1, + optVals, + "PostUpdateMac"); + + NSTask *task = [[NSTask alloc] init]; + [task setLaunchPath:exeFullPath]; + [task setArguments:[NSArray arrayWithObject:exeArg]]; + [task launch]; + if (!readResult) { + NSString *exeAsync = [NSString stringWithUTF8String:optVals[0]]; + if ([exeAsync isEqualToString:@"false"]) { + [task waitUntilExit]; + } + } + // ignore the return value of the task, there's nothing we can do with it + [task release]; +} + +id ConnectToUpdateServer() +{ + MacAutoreleasePool pool; + + id updateServer = nil; + BOOL isConnected = NO; + int currTry = 0; + const int numRetries = 10; // Number of IPC connection retries before + // giving up. + while (!isConnected && currTry < numRetries) { + @try { + updateServer = (id)[NSConnection + rootProxyForConnectionWithRegisteredName: + @"org.mozilla.updater.server" + host:nil + usingNameServer:[NSSocketPortNameServer sharedInstance]]; + if (!updateServer || + ![updateServer respondsToSelector:@selector(abort)] || + ![updateServer respondsToSelector:@selector(getArguments)] || + ![updateServer respondsToSelector:@selector(shutdown)]) { + NSLog(@"Server doesn't exist or doesn't provide correct selectors."); + sleep(1); // Wait 1 second. + currTry++; + } else { + isConnected = YES; + } + } @catch (NSException* e) { + NSLog(@"Encountered exception, retrying: %@: %@", e.name, e.reason); + sleep(1); // Wait 1 second. + currTry++; + } + } + if (!isConnected) { + NSLog(@"Failed to connect to update server after several retries."); + return nil; + } + return updateServer; +} + +void CleanupElevatedMacUpdate(bool aFailureOccurred) +{ + MacAutoreleasePool pool; + + id updateServer = ConnectToUpdateServer(); + if (updateServer) { + @try { + if (aFailureOccurred) { + [updateServer performSelector:@selector(abort)]; + } else { + [updateServer performSelector:@selector(shutdown)]; + } + } @catch (NSException* e) { } + } + + NSFileManager* manager = [NSFileManager defaultManager]; + [manager removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater" + error:nil]; + [manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist" + error:nil]; + const char* launchctlArgs[] = {"/bin/launchctl", + "remove", + "org.mozilla.updater"}; + // The following call will terminate the current process due to the "remove" + // argument in launchctlArgs. + LaunchChild(3, launchctlArgs); +} + +// Note: Caller is responsible for freeing argv. +bool ObtainUpdaterArguments(int* argc, char*** argv) +{ + MacAutoreleasePool pool; + + id updateServer = ConnectToUpdateServer(); + if (!updateServer) { + // Let's try our best and clean up. + CleanupElevatedMacUpdate(true); + return false; // Won't actually get here due to CleanupElevatedMacUpdate. + } + + @try { + NSArray* updaterArguments = + [updateServer performSelector:@selector(getArguments)]; + *argc = [updaterArguments count]; + char** tempArgv = (char**)malloc(sizeof(char*) * (*argc)); + for (int i = 0; i < *argc; i++) { + int argLen = [[updaterArguments objectAtIndex:i] length] + 1; + tempArgv[i] = (char*)malloc(argLen); + strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], + argLen); + } + *argv = tempArgv; + } @catch (NSException* e) { + // Let's try our best and clean up. + CleanupElevatedMacUpdate(true); + return false; // Won't actually get here due to CleanupElevatedMacUpdate. + } + return true; +} + +/** + * The ElevatedUpdateServer is launched from a non-elevated updater process. + * It allows an elevated updater process (usually a privileged helper tool) to + * connect to it and receive all the necessary arguments to complete a + * successful update. + */ +@interface ElevatedUpdateServer : NSObject +{ + NSArray* mUpdaterArguments; + BOOL mShouldKeepRunning; + BOOL mAborted; +} +- (id)initWithArgs:(NSArray*)args; +- (BOOL)runServer; +- (NSArray*)getArguments; +- (void)abort; +- (BOOL)wasAborted; +- (void)shutdown; +- (BOOL)shouldKeepRunning; +@end + +@implementation ElevatedUpdateServer + +- (id)initWithArgs:(NSArray*)args +{ + self = [super init]; + if (!self) { + return nil; + } + mUpdaterArguments = args; + mShouldKeepRunning = YES; + mAborted = NO; + return self; +} + +- (BOOL)runServer +{ + NSPort* serverPort = [NSSocketPort port]; + NSConnection* server = [NSConnection connectionWithReceivePort:serverPort + sendPort:serverPort]; + [server setRootObject:self]; + if ([server registerName:@"org.mozilla.updater.server" + withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) { + NSLog(@"Unable to register as DirectoryServer."); + NSLog(@"Is another copy running?"); + return NO; + } + + while ([self shouldKeepRunning] && + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode + beforeDate:[NSDate distantFuture]]); + return ![self wasAborted]; +} + +- (NSArray*)getArguments +{ + return mUpdaterArguments; +} + +- (void)abort +{ + mAborted = YES; + [self shutdown]; +} + +- (BOOL)wasAborted +{ + return mAborted; +} + +- (void)shutdown +{ + mShouldKeepRunning = NO; +} + +- (BOOL)shouldKeepRunning +{ + return mShouldKeepRunning; +} + +@end + +bool ServeElevatedUpdate(int argc, const char** argv) +{ + MacAutoreleasePool pool; + + NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:argc]; + for (int i = 0; i < argc; i++) { + [updaterArguments addObject:[NSString stringWithUTF8String:argv[i]]]; + } + + ElevatedUpdateServer* updater = + [[ElevatedUpdateServer alloc] initWithArgs:[updaterArguments copy]]; + bool didSucceed = [updater runServer]; + + [updater release]; + return didSucceed; +} + +bool IsOwnedByGroupAdmin(const char* aAppBundle) +{ + MacAutoreleasePool pool; + + NSString* appDir = [NSString stringWithUTF8String:aAppBundle]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + + NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir + error:nil]; + bool isOwnedByAdmin = false; + if (attributes && + [[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) { + isOwnedByAdmin = true; + } + return isOwnedByAdmin; +} + +void SetGroupOwnershipAndPermissions(const char* aAppBundle) +{ + MacAutoreleasePool pool; + + NSString* appDir = [NSString stringWithUTF8String:aAppBundle]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSError* error = nil; + NSArray* paths = + [fileManager subpathsOfDirectoryAtPath:appDir + error:&error]; + if (error) { + return; + } + + // Set group ownership of Firefox.app to 80 ("admin") and permissions to + // 0775. + if (![fileManager setAttributes:@{ NSFileGroupOwnerAccountID: @(80), + NSFilePosixPermissions: @(0775) } + ofItemAtPath:appDir + error:&error] || error) { + return; + } + + NSArray* permKeys = [NSArray arrayWithObjects:NSFileGroupOwnerAccountID, + NSFilePosixPermissions, + nil]; + // For all descendants of Firefox.app, set group ownership to 80 ("admin") and + // ensure write permission for the group. + for (NSString* currPath in paths) { + NSString* child = [appDir stringByAppendingPathComponent:currPath]; + NSDictionary* oldAttributes = + [fileManager attributesOfItemAtPath:child + error:&error]; + if (error) { + return; + } + // Skip symlinks, since they could be pointing to files outside of the .app + // bundle. + if ([oldAttributes fileType] == NSFileTypeSymbolicLink) { + continue; + } + NSNumber* oldPerms = + (NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions]; + NSArray* permObjects = + [NSArray arrayWithObjects: + [NSNumber numberWithUnsignedLong:80], + [NSNumber numberWithUnsignedLong:[oldPerms shortValue] | 020], + nil]; + NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects + forKeys:permKeys]; + if (![fileManager setAttributes:attributes + ofItemAtPath:child + error:&error] || error) { + return; + } + } +} diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Info.plist.in b/toolkit/mozapps/update/updater/macbuild/Contents/Info.plist.in new file mode 100644 index 0000000000..a9b9fcba9d --- /dev/null +++ b/toolkit/mozapps/update/updater/macbuild/Contents/Info.plist.in @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + org.mozilla.updater + CFBundleIconFile + updater.icns + CFBundleIdentifier + org.mozilla.updater + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + LSMinimumSystemVersion + 10.5 + LSMinimumSystemVersionByArchitecture + + i386 + 10.5.0 + x86_64 + 10.6.0 + + SMAuthorizedClients + + identifier "%MOZ_MACBUNDLE_ID%" and ((anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9]) or (anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "43AQ936H96")) + + + diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo b/toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo new file mode 100644 index 0000000000..bd04210fb4 --- /dev/null +++ b/toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in new file mode 100644 index 0000000000..bca4022e75 --- /dev/null +++ b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Localized versions of Info.plist keys */ + +CFBundleName = "%APP_NAME% Software Update"; diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 0000000000..6cfb50406b --- /dev/null +++ b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,19 @@ +{ + IBClasses = ( + { + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; +}, + { + CLASS = UpdaterUI; + LANGUAGE = ObjC; + OUTLETS = { + progressBar = NSProgressIndicator; + progressTextField = NSTextField; + }; + SUPERCLASS = NSObject; +} + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 0000000000..1509178370 --- /dev/null +++ b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,22 @@ + + + + + IBDocumentLocation + 111 162 356 240 0 0 1440 878 + IBEditorPositions + + 29 + 106 299 84 44 0 0 1440 878 + + IBFramework Version + 489.0 + IBOpenObjects + + 21 + 29 + + IBSystem Version + 10J567 + + diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000000..61ff026009 Binary files /dev/null and b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/toolkit/mozapps/update/updater/macbuild/Contents/Resources/updater.icns b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/updater.icns new file mode 100644 index 0000000000..d7499c6692 Binary files /dev/null and b/toolkit/mozapps/update/updater/macbuild/Contents/Resources/updater.icns differ diff --git a/toolkit/mozapps/update/updater/moz.build b/toolkit/mozapps/update/updater/moz.build index 6cf377afef..4dc557ea34 100644 --- a/toolkit/mozapps/update/updater/moz.build +++ b/toolkit/mozapps/update/updater/moz.build @@ -3,13 +3,26 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -Program('updater') +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + Program('org.mozilla.updater') +else: + Program('updater') updater_rel_path = '' include('updater-common.build') CXXFLAGS += CONFIG['MOZ_BZ2_CFLAGS'] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + LDFLAGS += ['-sectcreate', + '__TEXT', + '__info_plist', + TOPOBJDIR + '/dist/bin/Info.plist', + '-sectcreate', + '__TEXT', + '__launchd_plist', + SRCDIR + '/Launchd.plist'] + GENERATED_FILES = [ 'primaryCert.h', 'secondaryCert.h', diff --git a/toolkit/mozapps/update/updater/progressui_osx.mm b/toolkit/mozapps/update/updater/progressui_osx.mm new file mode 100644 index 0000000000..54c9c41b72 --- /dev/null +++ b/toolkit/mozapps/update/updater/progressui_osx.mm @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#include +#include +#include "mozilla/Sprintf.h" +#include "progressui.h" +#include "readstrings.h" +#include "errors.h" + +#define TIMER_INTERVAL 0.2 + +static float sProgressVal; // between 0 and 100 +static BOOL sQuit = NO; +static BOOL sIndeterminate = NO; +static StringTable sLabels; +static const char *sUpdatePath; + +@interface UpdaterUI : NSObject +{ + IBOutlet NSProgressIndicator *progressBar; + IBOutlet NSTextField *progressTextField; +} +@end + +@implementation UpdaterUI + +-(void)awakeFromNib +{ + NSWindow *w = [progressBar window]; + + [w setTitle:[NSString stringWithUTF8String:sLabels.title]]; + [progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info]]; + + NSRect origTextFrame = [progressTextField frame]; + [progressTextField sizeToFit]; + + int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width; + + if (widthAdjust > 0) { + NSRect f; + f.size.width = w.frame.size.width + widthAdjust; + f.size.height = w.frame.size.height; + [w setFrame:f display:YES]; + } + + [w center]; + + [progressBar setIndeterminate:sIndeterminate]; + [progressBar setDoubleValue:0.0]; + + [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self + selector:@selector(updateProgressUI:) + userInfo:nil repeats:YES] retain]; + + // Make sure we are on top initially + [NSApp activateIgnoringOtherApps:YES]; +} + +// called when the timer goes off +-(void)updateProgressUI:(NSTimer *)aTimer +{ + if (sQuit) { + [aTimer invalidate]; + [aTimer release]; + + // It seems to be necessary to activate and hide ourselves before we stop, + // otherwise the "run" method will not return until the user focuses some + // other app. The activate step is necessary if we are not the active app. + // This is a big hack, but it seems to do the trick. + [NSApp activateIgnoringOtherApps:YES]; + [NSApp hide:self]; + [NSApp stop:self]; + } + + float progress = sProgressVal; + + [progressBar setDoubleValue:(double)progress]; +} + +// leave this as returning a BOOL instead of NSApplicationTerminateReply +// for backward compatibility +- (BOOL)applicationShouldTerminate:(NSApplication *)sender +{ + return sQuit; +} + +@end + +int +InitProgressUI(int *pargc, char ***pargv) +{ + sUpdatePath = (*pargv)[1]; + + return 0; +} + +int +ShowProgressUI(bool indeterminate) +{ + // Only show the Progress UI if the process is taking a significant amount of + // time where a significant amount of time is defined as .5 seconds after + // ShowProgressUI is called sProgress is less than 70. + usleep(500000); + + if (sQuit || sProgressVal > 70.0f) + return 0; + + char path[PATH_MAX]; + SprintfLiteral(path, "%s/updater.ini", sUpdatePath); + if (ReadStrings(path, &sLabels) != OK) + return -1; + + // Continue the update without showing the Progress UI if any of the supplied + // strings are larger than MAX_TEXT_LEN (Bug 628829). + if (!(strlen(sLabels.title) < MAX_TEXT_LEN - 1 && + strlen(sLabels.info) < MAX_TEXT_LEN - 1)) + return -1; + + sIndeterminate = indeterminate; + [NSApplication sharedApplication]; + [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; + [NSApp run]; + + return 0; +} + +// Called on a background thread +void +QuitProgressUI() +{ + sQuit = YES; +} + +// Called on a background thread +void +UpdateProgressUI(float progress) +{ + sProgressVal = progress; // 32-bit writes are atomic +} diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build index 1ace8fcc71..ce4a219001 100644 --- a/toolkit/mozapps/update/updater/updater-common.build +++ b/toolkit/mozapps/update/updater/updater-common.build @@ -73,6 +73,24 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: 'progressui_gtk.cpp', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + have_progressui = 1 + srcs += [ + 'launchchild_osx.mm', + 'progressui_osx.mm', + ] + OS_LIBS += [ + '-framework Cocoa', + '-framework Security', + '-framework SystemConfiguration', + ] + UNIFIED_SOURCES += [ + '/toolkit/xre/updaterfileutils_osx.mm', + ] + LOCAL_INCLUDES += [ + '/toolkit/xre', + ] + if have_progressui == 0: srcs += [ 'progressui_null.cpp', diff --git a/toolkit/system/osxproxy/ProxyUtils.h b/toolkit/system/osxproxy/ProxyUtils.h new file mode 100644 index 0000000000..d6e5ddbd45 --- /dev/null +++ b/toolkit/system/osxproxy/ProxyUtils.h @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_toolkit_system_osxproxy_ProxyUtils_h +#define mozilla_toolkit_system_osxproxy_ProxyUtils_h + +#include "nsStringGlue.h" + +namespace mozilla { +namespace toolkit { +namespace system { + +bool IsHostProxyEntry(const nsACString& aHost, const nsACString& aOverride); + +} // namespace system +} // namespace toolkit +} // namespace mozilla + +#endif // mozilla_toolkit_system_osxproxy_ProxyUtils_h diff --git a/toolkit/system/osxproxy/ProxyUtils.mm b/toolkit/system/osxproxy/ProxyUtils.mm new file mode 100644 index 0000000000..4e59f226a0 --- /dev/null +++ b/toolkit/system/osxproxy/ProxyUtils.mm @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ProxyUtils.h" +#include "nsTArray.h" +#include "prnetdb.h" +#include "prtypes.h" + +namespace mozilla { +namespace toolkit { +namespace system { + +/** + * Normalize the short IP form into the complete form. + * For example, it converts "192.168" into "192.168.0.0" + */ +static bool +NormalizeAddr(const nsACString& aAddr, nsCString& aNormalized) +{ + nsTArray addr; + if (!ParseString(aAddr, '.', addr)) { + return false; + } + aNormalized = ""; + for (uint32_t i = 0; i < 4; ++i) { + if (i != 0) { + aNormalized.Append("."); + } + if (i < addr.Length()) { + aNormalized.Append(addr[i]); + } else { + aNormalized.Append("0"); + } + } + return true; +} + +static PRUint32 +MaskIPv4Addr(PRUint32 aAddr, uint16_t aMaskLen) +{ + if (aMaskLen == 32) { + return aAddr; + } + return PR_htonl(PR_ntohl(aAddr) & (~0L << (32 - aMaskLen))); +} + +static void +MaskIPv6Addr(PRIPv6Addr& aAddr, uint16_t aMaskLen) +{ + if (aMaskLen == 128) { + return; + } + + if (aMaskLen > 96) { + aAddr.pr_s6_addr32[3] = PR_htonl( + PR_ntohl(aAddr.pr_s6_addr32[3]) & (~0L << (128 - aMaskLen))); + } else if (aMaskLen > 64) { + aAddr.pr_s6_addr32[3] = 0; + aAddr.pr_s6_addr32[2] = PR_htonl( + PR_ntohl(aAddr.pr_s6_addr32[2]) & (~0L << (96 - aMaskLen))); + } else if (aMaskLen > 32) { + aAddr.pr_s6_addr32[3] = 0; + aAddr.pr_s6_addr32[2] = 0; + aAddr.pr_s6_addr32[1] = PR_htonl( + PR_ntohl(aAddr.pr_s6_addr32[1]) & (~0L << (64 - aMaskLen))); + } else { + aAddr.pr_s6_addr32[3] = 0; + aAddr.pr_s6_addr32[2] = 0; + aAddr.pr_s6_addr32[1] = 0; + aAddr.pr_s6_addr32[0] = PR_htonl( + PR_ntohl(aAddr.pr_s6_addr32[0]) & (~0L << (32 - aMaskLen))); + } + + return; +} + +static bool +IsMatchMask(const nsACString& aHost, const nsACString& aOverride) +{ + nsresult rv; + + auto tokenEnd = aOverride.FindChar('/'); + if (tokenEnd == -1) { + return false; + } + + nsAutoCString prefixStr(Substring(aOverride, + tokenEnd + 1, + aOverride.Length() - tokenEnd - 1)); + auto maskLen = prefixStr.ToInteger(&rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + nsAutoCString override(aOverride); + if (!NormalizeAddr(Substring(aOverride, 0, tokenEnd), override)) { + return false; + } + + PRNetAddr prAddrHost; + PRNetAddr prAddrOverride; + if (PR_SUCCESS != PR_StringToNetAddr(PromiseFlatCString(aHost).get(), + &prAddrHost) || + PR_SUCCESS != PR_StringToNetAddr(override.get(), + &prAddrOverride)) { + return false; + } + + if (prAddrHost.raw.family == PR_AF_INET && + prAddrOverride.raw.family == PR_AF_INET) { + return MaskIPv4Addr(prAddrHost.inet.ip, maskLen) == + MaskIPv4Addr(prAddrOverride.inet.ip, maskLen); + } + else if (prAddrHost.raw.family == PR_AF_INET6 && + prAddrOverride.raw.family == PR_AF_INET6) { + MaskIPv6Addr(prAddrHost.ipv6.ip, maskLen); + MaskIPv6Addr(prAddrOverride.ipv6.ip, maskLen); + + return memcmp(&prAddrHost.ipv6.ip, + &prAddrOverride.ipv6.ip, + sizeof(PRIPv6Addr)) == 0; + } + + return false; +} + +static bool +IsMatchWildcard(const nsACString& aHost, const nsACString& aOverride) +{ + nsAutoCString host(aHost); + nsAutoCString override(aOverride); + + int32_t overrideLength = override.Length(); + int32_t tokenStart = 0; + int32_t offset = 0; + bool star = false; + + while (tokenStart < overrideLength) { + int32_t tokenEnd = override.FindChar('*', tokenStart); + if (tokenEnd == tokenStart) { + // Star is the first character in the token. + star = true; + tokenStart++; + // If the character following the '*' is a '.' character then skip + // it so that "*.foo.com" allows "foo.com". + if (override.FindChar('.', tokenStart) == tokenStart) { + nsAutoCString token(Substring(override, + tokenStart + 1, + overrideLength - tokenStart - 1)); + if (host.Equals(token)) { + return true; + } + } + } else { + if (tokenEnd == -1) { + tokenEnd = overrideLength; // no '*' char, match rest of string + } + nsAutoCString token(Substring(override, tokenStart, tokenEnd - tokenStart)); + offset = host.Find(token, offset); + if (offset == -1 || (!star && offset)) { + return false; + } + star = false; + tokenStart = tokenEnd; + offset += token.Length(); + } + } + + return (star || (offset == static_cast(host.Length()))); +} + +bool +IsHostProxyEntry(const nsACString& aHost, const nsACString& aOverride) +{ + return IsMatchMask(aHost, aOverride) || IsMatchWildcard(aHost, aOverride); +} + +} // namespace system +} // namespace toolkit +} // namespace mozilla diff --git a/toolkit/system/osxproxy/moz.build b/toolkit/system/osxproxy/moz.build new file mode 100644 index 0000000000..64a01ce6b8 --- /dev/null +++ b/toolkit/system/osxproxy/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +TEST_DIRS += ['tests/gtest'] + +SOURCES += [ + 'nsOSXSystemProxySettings.mm', + 'ProxyUtils.mm', +] + +FINAL_LIBRARY = 'xul' diff --git a/toolkit/system/osxproxy/nsOSXSystemProxySettings.mm b/toolkit/system/osxproxy/nsOSXSystemProxySettings.mm new file mode 100644 index 0000000000..77fd2e482c --- /dev/null +++ b/toolkit/system/osxproxy/nsOSXSystemProxySettings.mm @@ -0,0 +1,326 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#import + +#include "nsISystemProxySettings.h" +#include "mozilla/ModuleUtils.h" +#include "nsIServiceManager.h" +#include "nsPrintfCString.h" +#include "nsNetCID.h" +#include "nsISupportsPrimitives.h" +#include "nsIURI.h" +#include "nsObjCExceptions.h" +#include "mozilla/Attributes.h" +#include "ProxyUtils.h" + +class nsOSXSystemProxySettings final : public nsISystemProxySettings { +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISYSTEMPROXYSETTINGS + + nsOSXSystemProxySettings(); + nsresult Init(); + + // called by OSX when the proxy settings have changed + void ProxyHasChanged(); + + // is there a PAC url specified in the system configuration + bool IsAutoconfigEnabled() const; + // retrieve the pac url + nsresult GetAutoconfigURL(nsAutoCString& aResult) const; + + // Find the SystemConfiguration proxy & port for a given URI + nsresult FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy); + + // is host:port on the proxy exception list? + bool IsInExceptionList(const nsACString& aHost) const; + +private: + ~nsOSXSystemProxySettings(); + + SCDynamicStoreContext mContext; + SCDynamicStoreRef mSystemDynamicStore; + NSDictionary* mProxyDict; + + + // Mapping of URI schemes to SystemConfiguration keys + struct SchemeMapping { + const char* mScheme; + CFStringRef mEnabled; + CFStringRef mHost; + CFStringRef mPort; + bool mIsSocksProxy; + }; + static const SchemeMapping gSchemeMappingList[]; +}; + +NS_IMPL_ISUPPORTS(nsOSXSystemProxySettings, nsISystemProxySettings) + +NS_IMETHODIMP +nsOSXSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) +{ + *aMainThreadOnly = true; + return NS_OK; +} + +// Mapping of URI schemes to SystemConfiguration keys +const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = { + {"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort, false}, + {"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort, false}, + {"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, false}, + {"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort, true}, + {NULL, NULL, NULL, NULL, false}, +}; + +static void +ProxyHasChangedWrapper(SCDynamicStoreRef aStore, CFArrayRef aChangedKeys, void* aInfo) +{ + static_cast(aInfo)->ProxyHasChanged(); +} + + +nsOSXSystemProxySettings::nsOSXSystemProxySettings() + : mSystemDynamicStore(NULL), mProxyDict(NULL) +{ + mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL}; +} + +nsresult +nsOSXSystemProxySettings::Init() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + // Register for notification of proxy setting changes + // See: http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html + mSystemDynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Mozilla"), ProxyHasChangedWrapper, &mContext); + if (!mSystemDynamicStore) + return NS_ERROR_FAILURE; + + // Set up the store to monitor any changes to the proxies + CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL); + if (!proxiesKey) + return NS_ERROR_FAILURE; + + CFArrayRef keyArray = CFArrayCreate(NULL, (const void**)(&proxiesKey), 1, &kCFTypeArrayCallBacks); + CFRelease(proxiesKey); + if (!keyArray) + return NS_ERROR_FAILURE; + + SCDynamicStoreSetNotificationKeys(mSystemDynamicStore, keyArray, NULL); + CFRelease(keyArray); + + // Add the dynamic store to the run loop + CFRunLoopSourceRef storeRLSource = SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0); + if (!storeRLSource) + return NS_ERROR_FAILURE; + CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource, kCFRunLoopCommonModes); + CFRelease(storeRLSource); + + // Load the initial copy of proxy info + mProxyDict = (NSDictionary*)SCDynamicStoreCopyProxies(mSystemDynamicStore); + if (!mProxyDict) + return NS_ERROR_FAILURE; + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +nsOSXSystemProxySettings::~nsOSXSystemProxySettings() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [mProxyDict release]; + + if (mSystemDynamicStore) { + // Invalidate the dynamic store's run loop source + // to get the store out of the run loop + CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0); + if (rls) { + CFRunLoopSourceInvalidate(rls); + CFRelease(rls); + } + CFRelease(mSystemDynamicStore); + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + + +void +nsOSXSystemProxySettings::ProxyHasChanged() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + [mProxyDict release]; + mProxyDict = (NSDictionary*)SCDynamicStoreCopyProxies(mSystemDynamicStore); + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +nsresult +nsOSXSystemProxySettings::FindSCProxyPort(const nsACString &aScheme, nsACString& aResultHost, int32_t& aResultPort, bool& aResultSocksProxy) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE); + + for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) { + // Check for matching scheme (when appropriate) + if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) && + !keys->mIsSocksProxy) + continue; + + // Check the proxy is enabled + NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled]; + NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]], NS_ERROR_FAILURE); + if ([enabled intValue] == 0) + continue; + + // Get the proxy host + NSString* host = [mProxyDict objectForKey:(NSString*)keys->mHost]; + if (host == NULL) + break; + NS_ENSURE_TRUE([host isKindOfClass:[NSString class]], NS_ERROR_FAILURE); + aResultHost.Assign([host UTF8String]); + + // Get the proxy port + NSNumber* port = [mProxyDict objectForKey:(NSString*)keys->mPort]; + NS_ENSURE_TRUE([port isKindOfClass:[NSNumber class]], NS_ERROR_FAILURE); + aResultPort = [port intValue]; + + aResultSocksProxy = keys->mIsSocksProxy; + + return NS_OK; + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +bool +nsOSXSystemProxySettings::IsAutoconfigEnabled() const +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + NSNumber* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable]; + NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]], false); + return ([value intValue] != 0); + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); +} + +nsresult +nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) const +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + NSString* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString]; + if (value != NULL) { + NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE); + aResult.Assign([value UTF8String]); + return NS_OK; + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +bool +nsOSXSystemProxySettings::IsInExceptionList(const nsACString& aHost) const +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; + + NS_ENSURE_TRUE(mProxyDict != NULL, false); + + NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList]; + NS_ENSURE_TRUE(exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]], false); + + NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator]; + NSString* currentValue = NULL; + while ((currentValue = [exceptionEnumerator nextObject])) { + NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false); + nsAutoCString overrideStr([currentValue UTF8String]); + if (mozilla::toolkit::system::IsHostProxyEntry(aHost, overrideStr)) + return true; + } + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); +} + +nsresult +nsOSXSystemProxySettings::GetPACURI(nsACString& aResult) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE); + + nsAutoCString pacUrl; + if (IsAutoconfigEnabled() && NS_SUCCEEDED(GetAutoconfigURL(pacUrl))) { + aResult.Assign(pacUrl); + return NS_OK; + } + + return NS_ERROR_FAILURE; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +nsresult +nsOSXSystemProxySettings::GetProxyForURI(const nsACString & aSpec, + const nsACString & aScheme, + const nsACString & aHost, + const int32_t aPort, + nsACString & aResult) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + int32_t proxyPort; + nsAutoCString proxyHost; + bool proxySocks; + nsresult rv = FindSCProxyPort(aScheme, proxyHost, proxyPort, proxySocks); + + if (NS_FAILED(rv) || IsInExceptionList(aHost)) { + aResult.AssignLiteral("DIRECT"); + } else if (proxySocks) { + aResult.Assign(NS_LITERAL_CSTRING("SOCKS ") + proxyHost + nsPrintfCString(":%d", proxyPort)); + } else { + aResult.Assign(NS_LITERAL_CSTRING("PROXY ") + proxyHost + nsPrintfCString(":%d", proxyPort)); + } + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +#define NS_OSXSYSTEMPROXYSERVICE_CID /* 9afcd4b8-2e0f-41f4-8f1f-3bf0d3cf67de */\ + { 0x9afcd4b8, 0x2e0f, 0x41f4, \ + { 0x8f, 0x1f, 0x3b, 0xf0, 0xd3, 0xcf, 0x67, 0xde } } + +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsOSXSystemProxySettings, Init); +NS_DEFINE_NAMED_CID(NS_OSXSYSTEMPROXYSERVICE_CID); + +static const mozilla::Module::CIDEntry kOSXSysProxyCIDs[] = { + { &kNS_OSXSYSTEMPROXYSERVICE_CID, false, NULL, nsOSXSystemProxySettingsConstructor }, + { NULL } +}; + +static const mozilla::Module::ContractIDEntry kOSXSysProxyContracts[] = { + { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_OSXSYSTEMPROXYSERVICE_CID }, + { NULL } +}; + +static const mozilla::Module kOSXSysProxyModule = { + mozilla::Module::kVersion, + kOSXSysProxyCIDs, + kOSXSysProxyContracts +}; + +NSMODULE_DEFN(nsOSXProxyModule) = &kOSXSysProxyModule; diff --git a/toolkit/system/osxproxy/tests/gtest/TestProxyBypassRules.cpp b/toolkit/system/osxproxy/tests/gtest/TestProxyBypassRules.cpp new file mode 100644 index 0000000000..7903491090 --- /dev/null +++ b/toolkit/system/osxproxy/tests/gtest/TestProxyBypassRules.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "ProxyUtils.h" + +using namespace mozilla::toolkit::system; + +TEST(OSXProxy, TestProxyBypassRules) +{ + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("mozilla.org"), NS_LITERAL_CSTRING("mozilla.org"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("mozilla.org"),NS_LITERAL_CSTRING("*mozilla.org"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("mozilla.org"), NS_LITERAL_CSTRING("*.mozilla.org"))); + EXPECT_FALSE(IsHostProxyEntry(NS_LITERAL_CSTRING("notmozilla.org"), NS_LITERAL_CSTRING("*.mozilla.org"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("www.mozilla.org"), NS_LITERAL_CSTRING("*mozilla.org"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("www.mozilla.org"), NS_LITERAL_CSTRING("*.mozilla.org"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("www.mozilla.com"), NS_LITERAL_CSTRING("*.mozilla.*"))); +} + +TEST(OSXProxy, TestProxyBypassRulesIPv4) +{ + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.1.1"), NS_LITERAL_CSTRING("192.168.1.*"))); + EXPECT_FALSE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.1.1"), NS_LITERAL_CSTRING("192.168.2.*"))); + + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("10.1.2.3"), NS_LITERAL_CSTRING("10.0.0.0/8"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.192.1"), NS_LITERAL_CSTRING("192.168/16"))); + EXPECT_FALSE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.192.1"), NS_LITERAL_CSTRING("192.168/17"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.192.1"), NS_LITERAL_CSTRING("192.168.128/17"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("192.168.1.1"), NS_LITERAL_CSTRING("192.168.1.1/32"))); +} + +TEST(OSXProxy, TestProxyBypassRulesIPv6) +{ + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("2001:0DB8:ABCD:0012:0123:4567:89AB:CDEF"), NS_LITERAL_CSTRING("2001:db8:abcd:0012::0/64"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("2001:0DB8:ABCD:0012:0000:4567:89AB:CDEF"), NS_LITERAL_CSTRING("2001:db8:abcd:0012::0/80"))); + EXPECT_FALSE(IsHostProxyEntry(NS_LITERAL_CSTRING("2001:0DB8:ABCD:0012:0123:4567:89AB:CDEF"), NS_LITERAL_CSTRING("2001:db8:abcd:0012::0/80"))); + EXPECT_TRUE(IsHostProxyEntry(NS_LITERAL_CSTRING("2001:0DB8:ABCD:0012:0000:0000:89AB:CDEF"), NS_LITERAL_CSTRING("2001:db8:abcd:0012::0/96"))); + EXPECT_FALSE(IsHostProxyEntry(NS_LITERAL_CSTRING("2001:0DB8:ABCD:0012:0123:4567:89AB:CDEF"), NS_LITERAL_CSTRING("2001:db8:abcd:0012::0/96"))); +} diff --git a/toolkit/system/osxproxy/tests/gtest/moz.build b/toolkit/system/osxproxy/tests/gtest/moz.build new file mode 100644 index 0000000000..94768a204e --- /dev/null +++ b/toolkit/system/osxproxy/tests/gtest/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'TestProxyBypassRules.cpp', +] + +LOCAL_INCLUDES += [ + '/toolkit/system/osxproxy', +] + +FINAL_LIBRARY = 'xul-gtest' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wshadow'] diff --git a/toolkit/themes/moz.build b/toolkit/themes/moz.build index b24036f1a0..74f53391e2 100644 --- a/toolkit/themes/moz.build +++ b/toolkit/themes/moz.build @@ -21,7 +21,9 @@ if CONFIG['MOZ_PHOENIX']: else: app = CONFIG['MOZ_BUILD_APP'] -if toolkit in ('gtk2', 'gtk3'): +if toolkit == 'cocoa': + DIRS += ['osx'] +elif toolkit in ('gtk2', 'gtk3'): DIRS += ['linux'] else: DIRS += ['windows'] diff --git a/toolkit/themes/osx/global/10pct_transparent_grey.png b/toolkit/themes/osx/global/10pct_transparent_grey.png new file mode 100644 index 0000000000..01f2edd9f4 Binary files /dev/null and b/toolkit/themes/osx/global/10pct_transparent_grey.png differ diff --git a/toolkit/themes/osx/global/50pct_transparent_grey.png b/toolkit/themes/osx/global/50pct_transparent_grey.png new file mode 100644 index 0000000000..0e462a46fa Binary files /dev/null and b/toolkit/themes/osx/global/50pct_transparent_grey.png differ diff --git a/toolkit/themes/osx/global/alerts/alert.css b/toolkit/themes/osx/global/alerts/alert.css new file mode 100644 index 0000000000..3ca1a6e066 --- /dev/null +++ b/toolkit/themes/osx/global/alerts/alert.css @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ===== alert.css ===================================================== + == Styles specific to the alerts dialog. + ======================================================================= */ + +@import url("chrome://global/skin/alerts/alert-common.css"); + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +#alertNotification { + -moz-appearance: none; + background: transparent; +} + +#alertBox { + border: 1px solid ThreeDShadow; + border-radius: 1px; + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +.alertCloseButton { + -moz-appearance: none; + padding: 0; + margin: 2px; + border: none; +} diff --git a/toolkit/themes/osx/global/arrow.css b/toolkit/themes/osx/global/arrow.css new file mode 100644 index 0000000000..f8d14becab --- /dev/null +++ b/toolkit/themes/osx/global/arrow.css @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.up { + min-width: 0px; + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} +.up[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); +} + +.down { + min-width: 0px; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} +.down[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); +} + +.left { + min-width: 0px; + list-style-image: url("chrome://global/skin/arrow/arrow-lft.gif"); +} +.left[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif"); +} + +.right { + min-width: 0px; + list-style-image: url("chrome://global/skin/arrow/arrow-rit.gif"); +} +.right[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif"); +} diff --git a/toolkit/themes/osx/global/arrow/arrow-dn-dis.gif b/toolkit/themes/osx/global/arrow/arrow-dn-dis.gif new file mode 100644 index 0000000000..3d62e40063 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-dn-dis.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-dn-dis.png b/toolkit/themes/osx/global/arrow/arrow-dn-dis.png new file mode 100644 index 0000000000..a202fd85c9 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-dn-dis.png differ diff --git a/toolkit/themes/osx/global/arrow/arrow-dn-sharp.gif b/toolkit/themes/osx/global/arrow/arrow-dn-sharp.gif new file mode 100644 index 0000000000..206d7c19dd Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-dn-sharp.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-dn.gif b/toolkit/themes/osx/global/arrow/arrow-dn.gif new file mode 100644 index 0000000000..33849a6391 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-dn.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-dn.png b/toolkit/themes/osx/global/arrow/arrow-dn.png new file mode 100644 index 0000000000..91486a3e9a Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-dn.png differ diff --git a/toolkit/themes/osx/global/arrow/arrow-lft-dis.gif b/toolkit/themes/osx/global/arrow/arrow-lft-dis.gif new file mode 100644 index 0000000000..33243517b1 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-lft-dis.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-lft-hov.gif b/toolkit/themes/osx/global/arrow/arrow-lft-hov.gif new file mode 100644 index 0000000000..3367bde312 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-lft-hov.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-lft-sharp-end.gif b/toolkit/themes/osx/global/arrow/arrow-lft-sharp-end.gif new file mode 100644 index 0000000000..c22294ba21 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-lft-sharp-end.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-lft-sharp.gif b/toolkit/themes/osx/global/arrow/arrow-lft-sharp.gif new file mode 100644 index 0000000000..ae9b1dd0fb Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-lft-sharp.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-lft.gif b/toolkit/themes/osx/global/arrow/arrow-lft.gif new file mode 100644 index 0000000000..c5c362d89b Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-lft.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-rit-dis.gif b/toolkit/themes/osx/global/arrow/arrow-rit-dis.gif new file mode 100644 index 0000000000..cda95fe215 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-rit-dis.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-rit-hov.gif b/toolkit/themes/osx/global/arrow/arrow-rit-hov.gif new file mode 100644 index 0000000000..5010921adc Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-rit-hov.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-rit-sharp-end.gif b/toolkit/themes/osx/global/arrow/arrow-rit-sharp-end.gif new file mode 100644 index 0000000000..c1b3750d4c Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-rit-sharp-end.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-rit-sharp.gif b/toolkit/themes/osx/global/arrow/arrow-rit-sharp.gif new file mode 100644 index 0000000000..ca628ba69b Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-rit-sharp.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-rit.gif b/toolkit/themes/osx/global/arrow/arrow-rit.gif new file mode 100644 index 0000000000..dce39aecc1 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-rit.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-up-dis.gif b/toolkit/themes/osx/global/arrow/arrow-up-dis.gif new file mode 100644 index 0000000000..381dee3e5d Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-up-dis.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-up-sharp.gif b/toolkit/themes/osx/global/arrow/arrow-up-sharp.gif new file mode 100644 index 0000000000..883a4f95ca Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-up-sharp.gif differ diff --git a/toolkit/themes/osx/global/arrow/arrow-up.gif b/toolkit/themes/osx/global/arrow/arrow-up.gif new file mode 100644 index 0000000000..b8e09b21b8 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/arrow-up.gif differ diff --git a/toolkit/themes/osx/global/arrow/panelarrow-horizontal.png b/toolkit/themes/osx/global/arrow/panelarrow-horizontal.png new file mode 100644 index 0000000000..c110f8592d Binary files /dev/null and b/toolkit/themes/osx/global/arrow/panelarrow-horizontal.png differ diff --git a/toolkit/themes/osx/global/arrow/panelarrow-horizontal@2x.png b/toolkit/themes/osx/global/arrow/panelarrow-horizontal@2x.png new file mode 100644 index 0000000000..4cb7353e70 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/panelarrow-horizontal@2x.png differ diff --git a/toolkit/themes/osx/global/arrow/panelarrow-vertical.png b/toolkit/themes/osx/global/arrow/panelarrow-vertical.png new file mode 100644 index 0000000000..3986f9cbf5 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/panelarrow-vertical.png differ diff --git a/toolkit/themes/osx/global/arrow/panelarrow-vertical@2x.png b/toolkit/themes/osx/global/arrow/panelarrow-vertical@2x.png new file mode 100644 index 0000000000..a741dd0e16 Binary files /dev/null and b/toolkit/themes/osx/global/arrow/panelarrow-vertical@2x.png differ diff --git a/toolkit/themes/osx/global/autocomplete.css b/toolkit/themes/osx/global/autocomplete.css new file mode 100644 index 0000000000..7e05d2f29c --- /dev/null +++ b/toolkit/themes/osx/global/autocomplete.css @@ -0,0 +1,174 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +/* .padded is used by autocomplete widgets that don't have an icon. Gross. -dwh */ +textbox:not(.padded) { + cursor: default; + padding: 0; +} + +textbox[nomatch="true"][highlightnonmatches="true"] { + color: red; +} + +textbox:not(.padded) .textbox-input-box { + margin: 0 3px; +} + +.textbox-input-box { + -moz-box-align: center; +} + +/* ::::: history button ::::: */ + +.autocomplete-history-dropmarker { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; + padding: 0px; + list-style-image: url("chrome://global/skin/icons/autocomplete-dropmarker.png"); + margin: 0px; +} + +/* ::::: autocomplete popups ::::: */ + +panel[type="autocomplete"], +panel[type="autocomplete-richlistbox"], +.autocomplete-history-popup { + padding: 0px !important; + color: -moz-FieldText; + background-color: -moz-Field; + font: icon; + -moz-appearance: none; +} + +.autocomplete-history-popup { + max-height: 180px; +} + +/* ::::: tree ::::: */ + +.autocomplete-tree { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; +} + +.autocomplete-treecol { + -moz-appearance: none !important; + margin: 0 !important; + border: none !important; + padding: 0 !important; +} + +.autocomplete-treebody::-moz-tree-cell-text { + padding-left: 2px; +} + +.autocomplete-treebody::-moz-tree-row { + border-top: none; +} + +treechildren.autocomplete-treebody::-moz-tree-row(selected) { + background-color: Highlight; +} + +treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) { + color: HighlightText !important; +} + +.autocomplete-treebody::-moz-tree-image(treecolAutoCompleteValue) { + max-width: 16px; + height: 16px; +} + +/* ::::: richlistbox autocomplete ::::: */ + +.autocomplete-richlistbox { + -moz-appearance: none; + margin: 0; +} + +.ac-type-icon { + width: 16px; + height: 16px; + max-width: 16px; + max-height: 16px; + margin-inline-start: 16px; + margin-inline-end: 6px; +} + +.ac-site-icon { + width: 16px; + height: 16px; + max-width: 16px; + max-height: 16px; + margin-inline-start: 0; + margin-inline-end: 11px; + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); +} + +.ac-site-icon[selected] { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon-inverted.png"); +} + +@media (min-resolution: 2dppx) { + .ac-site-icon { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png"); + } + .ac-site-icon[selected] { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon-inverted@2x.png"); + } +} + +.ac-title { + margin-inline-start: 0; + margin-inline-end: 6px; +} + +html|span.ac-tag { + margin-inline-start: 0; + margin-inline-end: 2px; +} + +.ac-tags { + margin-inline-start: 0; + margin-inline-end: 4px; +} + +.ac-separator { + margin-inline-start: 0; + margin-inline-end: 6px; +} + +/* Better align the URL/action with the title. */ +.ac-tags, +.ac-separator, +.ac-url, +.ac-action { + margin-bottom: -2px; +} + +.ac-title-text, +.ac-tags-text, +.ac-separator-text, +.ac-url-text, +.ac-action-text, +.ac-text-overflow-container { + padding: 0 !important; + margin: 0 !important; +} + +/* ::::: textboxes inside toolbarpaletteitems ::::: */ + +toolbarpaletteitem > toolbaritem > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} + +toolbarpaletteitem > toolbaritem > * > textbox > hbox > hbox > html|*.textbox-input { + visibility: hidden; +} diff --git a/toolkit/themes/osx/global/button.css b/toolkit/themes/osx/global/button.css new file mode 100644 index 0000000000..45f292e1f1 --- /dev/null +++ b/toolkit/themes/osx/global/button.css @@ -0,0 +1,85 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +button { + -moz-appearance: button; + /* The horizontal margin used here come from the Aqua Human Interface + Guidelines, there should be 12 pixels between two buttons. */ + margin: 5px 6px 3px; + min-width: 79px; + color: ButtonText; + text-shadow: none; +} + +button:not([disabled="true"]):hover:active { + color: -moz-mac-buttonactivetext; +} + +/* When the window isn't focused, the default button background isn't drawn, + * so don't change the text color then: */ +button[default="true"]:not([disabled="true"]):not(:-moz-window-inactive) { + color: -moz-mac-defaultbuttontext; +} + +/* Likewise, when active (mousedown) but not hovering, the default button + * background isn't drawn, override the previous selector for that case: */ +button[default="true"]:not(:hover):active { + color: ButtonText; +} + +.button-text { + margin: 1px 0 !important; + margin-inline-start: 3px !important; + margin-inline-end: 2px !important; + text-align: center; +} + +.button-icon { + margin-inline-start: 1px; +} + +button[type="default"] { + font: menu; +} + +/* .......... disabled state .......... */ + +button[disabled="true"] { + color: GrayText; +} + +/* ::::: menu/menu-button buttons ::::: */ + +button[type="menu-button"] { + margin: 0; + border: none; +} + +.button-menu-dropmarker, +.button-menubutton-dropmarker { + -moz-appearance: none !important; + border: none; + background-color: transparent !important; + margin: 1px; +} + +.button-menu-dropmarker { + display: none; +} + +/* ::::: plain buttons ::::: */ + +button.plain { + margin: 0 !important; + padding: 0 !important; +} + +/* ::::: help button ::::: */ + +button[dlgtype="help"] { + -moz-appearance: -moz-mac-help-button; + width: 20px; +} diff --git a/toolkit/themes/osx/global/checkbox.css b/toolkit/themes/osx/global/checkbox.css new file mode 100644 index 0000000000..b49af98d04 --- /dev/null +++ b/toolkit/themes/osx/global/checkbox.css @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +checkbox { + -moz-appearance: checkbox-container; + -moz-box-align: center; + margin: 4px 2px; +} + +.checkbox-icon { + margin-right: 2px; +} + +.checkbox-label { + margin: 1px 0 !important; +} + +/* ..... disabled state ..... */ + +checkbox[disabled="true"] { + color: GrayText !important; +} + +/* ::::: checkmark image ::::: */ + +.checkbox-check { + -moz-appearance: checkbox; + margin: 1px 1px 0; + /* vertical-align tells native theming where to snap to. However, this doesn't + * always work reliably because of bug 503833. */ + vertical-align: top; + width: 1.3em; + height: 1.3em; +} + + diff --git a/toolkit/themes/osx/global/checkbox/cbox-check-dis.gif b/toolkit/themes/osx/global/checkbox/cbox-check-dis.gif new file mode 100644 index 0000000000..bd43dd17c3 Binary files /dev/null and b/toolkit/themes/osx/global/checkbox/cbox-check-dis.gif differ diff --git a/toolkit/themes/osx/global/checkbox/cbox-check.gif b/toolkit/themes/osx/global/checkbox/cbox-check.gif new file mode 100644 index 0000000000..f6919f8fad Binary files /dev/null and b/toolkit/themes/osx/global/checkbox/cbox-check.gif differ diff --git a/toolkit/themes/osx/global/colorpicker.css b/toolkit/themes/osx/global/colorpicker.css new file mode 100644 index 0000000000..075437db89 --- /dev/null +++ b/toolkit/themes/osx/global/colorpicker.css @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* ::::: colorpicker button ::::: */ + +colorpicker[type="button"] { + width: 38px; + height: 24px; + border: 1px solid #a7a7a7; + background-color: ThreeDFace; + padding: 3px; + -moz-appearance: button-bevel; +} + +.colorpicker-button-colorbox { + border: 1px solid #000000; +} + +/* ::::: colorpicker tiles ::::: */ + +.colorpickertile { + width : 20px; + height : 20px; + margin : 1px; +} + +.colorpickertile[selected="true"] { + border : 1px outset #C0C0C0; + +} + +.colorpickertile[hover="true"] { + border : 1px dotted #A7A7A7; +} + +.cp-light[hover="true"] { + border : 1px dotted #000000; +} diff --git a/toolkit/themes/osx/global/commonDialog.css b/toolkit/themes/osx/global/commonDialog.css new file mode 100644 index 0000000000..53b02796d2 --- /dev/null +++ b/toolkit/themes/osx/global/commonDialog.css @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#commonDialog { + line-height: 13px; +} + +#filler { + margin: 0px -14px; +} + +#infoContainer { + max-width: 33em; +} + +#loginContainer { + padding-top: 10px; +} + +#info\.icon { + margin-inline-end: 14px; +} + +#info\.title, +#info\.header, +#info\.body { + font: menu; + line-height: 16px; + margin-bottom: 6px; +} + +#info\.title { + font-weight: bold; +} diff --git a/toolkit/themes/osx/global/console/console-error-caret.gif b/toolkit/themes/osx/global/console/console-error-caret.gif new file mode 100644 index 0000000000..a8f30f9263 Binary files /dev/null and b/toolkit/themes/osx/global/console/console-error-caret.gif differ diff --git a/toolkit/themes/osx/global/console/console-error-dash.gif b/toolkit/themes/osx/global/console/console-error-dash.gif new file mode 100644 index 0000000000..74679a25e2 Binary files /dev/null and b/toolkit/themes/osx/global/console/console-error-dash.gif differ diff --git a/toolkit/themes/osx/global/console/console.css b/toolkit/themes/osx/global/console/console.css new file mode 100644 index 0000000000..f18f6f680c --- /dev/null +++ b/toolkit/themes/osx/global/console/console.css @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ===== console.css ==================================================== + == Styles used by the Error Console window. + ======================================================================= */ + +/* View buttons */ +@import "chrome://global/skin/viewbuttons.css"; + +%include ../shared.inc +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.console-box { + background-color: -moz-Field; + color: -moz-FieldText; + overflow: auto; +} + +/* ::::: console rows ::::: */ + +.console-row { + border-bottom: 1px solid #A3A3A3; + padding: 4px; +} + +.console-row-file { + color: #505050; +} + +.console-row-msg > label:first-child { + font-weight: bold; +} + +.console-row-msg > label, .comsole-row-msg > description, .console-error-msg, .console-row-file, .console-row-code { + margin: 2px; +} + +.console-row-file > label { + margin: 0; +} + +.console-msg-text { + white-space: pre-wrap !important; +} +.console-icon { + list-style-image: inherit; + padding-right: 6px; + padding-left: 6px; +} + +/* ..... error rows ..... */ + +.console-row-code { + color: #0000BB; + font-size: larger; +} + +.console-dots, +.console-caret { + height: 9px; +} + +.console-dots { + background: url("chrome://global/skin/console/console-error-dash.gif") repeat-x top; +} + +.console-caret { + width: 7px; + background: url("chrome://global/skin/console/console-error-caret.gif") no-repeat top; +} + +/* ..... message rows ..... */ + +.console-row[type="message"] { + font-family: monospace; +} + +/* ..... selected state ..... */ + +.console-row[selected="true"] { + background-color: #3D80DF !important; + color: #FFF; +} + +.console-row-code[selected="true"], +.console-row-content[selected="true"] > .console-row-file, +.console-row-content[selected="true"] > .console-row-file > .console-error-source > .text-link { + color: #FFF !important; +} + +/* ::::: row colors ::::: */ + +.console-row[type="error"], +.console-row[type="exception"] { + background-color: #FFD0DC; +} + +.console-row[type="warning"] { + background-color: #F8F3CC; +} + +.console-row[type="message"] { + background-color: #D3EDFF; +} + +/* ::::: toolbars ::::: */ + +#ToolbarEval { + -moz-appearance: none; + background: @scopeBarBackground@; + border-bottom: @scopeBarSeparatorBorder@; + padding: 2px; +} + +#ToolbarEval > label { + font-weight: bold; + color: @scopeBarTitleColor@; +} + +#TextfieldEval { + margin: 2px !important; +} + +#ButtonEval { + margin: 0 4px; + padding: 1px 10px; + -moz-appearance: none; + border-radius: 10000px; + border: @roundButtonBorder@; + background: @roundButtonBackground@; + box-shadow: @roundButtonShadow@; +} + +#ButtonEval:hover:active { + text-shadow: @loweredShadow@; + background: @roundButtonPressedBackground@; + box-shadow: @roundButtonPressedShadow@; +} + +toolbarseparator { + min-height: 1em; + background-image: none; +} + +/* Toolbar icons */ + +#ToolbarMode { + -moz-box-pack: center; +} + +#ToolbarMode toolbarbutton > .toolbarbutton-icon { + display: none; +} + +#Console\:clear { + -moz-box-orient: vertical; + -moz-box-align: center; + -moz-appearance: toolbarbutton; + font: menu; + text-shadow: @loweredShadow@; + margin: 4px 0 9px; + padding: 0 1px; +} diff --git a/toolkit/themes/osx/global/customizeToolbar.css b/toolkit/themes/osx/global/customizeToolbar.css new file mode 100644 index 0000000000..bcedb2b99a --- /dev/null +++ b/toolkit/themes/osx/global/customizeToolbar.css @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#palette-box { + margin-top: 2px; + -moz-appearance: listbox; + margin: 0 0 10px; +} + +#palette-box > toolbarpaletteitem { + padding: 8px 2px; + margin: 0 8px; +} + +#main-box { + padding: 12px; +} + +#main-box > separator { + -moz-appearance: none; + border-bottom: none; +} + +#instructions { + font: menu; + font-weight: bold; + line-height: 16pt; +} + +hbox button { + font: menu; +} + +#main-box > box > button { + min-height: 19px; /* aqua size for small buttons */ + font: message-box; +} diff --git a/toolkit/themes/osx/global/datetimepicker.css b/toolkit/themes/osx/global/datetimepicker.css new file mode 100644 index 0000000000..3d7b201f2e --- /dev/null +++ b/toolkit/themes/osx/global/datetimepicker.css @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +datepicker, timepicker { + padding: 0 0 1px; + margin: 4px; + border: none; +} + +.datetimepicker-input-box { + -moz-appearance: textfield; + cursor: text; + margin-right: 4px; + margin-bottom: 2px; + border: 3px solid; + -moz-border-top-colors: transparent #888888 #000000; + -moz-border-right-colors: transparent #FFFFFF #000000; + -moz-border-bottom-colors: transparent #FFFFFF #000000; + -moz-border-left-colors: transparent #888888 #000000; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + padding: 0px; + background-color: -moz-Field; + color: -moz-FieldText; +} + +.datetimepicker-input-subbox { + width: 1.6em; +} + +html|*.datetimepicker-input { + text-align: end; +} + +.datetimepicker-separator { + margin: 0 !important; +} + +.datetimepicker-year { + width: 3.2em; +} + +.datepicker-dropmarker { + margin-bottom: 2px; +} + +datepicker[readonly="true"], +timepicker[readonly="true"] { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +datepicker[disabled="true"], +timepicker[disabled="true"] { + cursor: default; + -moz-border-top-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-right-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-bottom-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-left-colors: transparent ThreeDShadow -moz-Dialog; + background-color: -moz-Dialog; + color: GrayText; +} + +.datepicker-mainbox { + margin: 2px 4px; + border: 2px solid; + -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow; + -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow; + background-color: #EEEEEE; + color: -moz-DialogText; +} + +.datepicker-popupgrid > .datepicker-mainbox { + margin: 0; + border: none; +} + +.datepicker-gridlabel, .datepicker-weeklabel { + text-align: center; +} + +.datepicker-gridlabel[today="true"] { + background-color: darkgrey; + color: white; +} + +.datepicker-gridlabel[selected="true"] { + background-color: Highlight; + color: HighlightText; +} + +.datepicker-button { + -moz-appearance: none; + min-width: 8px; + padding: 0px; +} + +.datepicker-previous { + list-style-image: url("chrome://global/skin/arrow/arrow-lft.gif"); +} + +.datepicker-next { + list-style-image: url("chrome://global/skin/arrow/arrow-rit.gif"); +} + +.datepicker-previous:hover { + list-style-image: url("chrome://global/skin/arrow/arrow-lft-hov.gif"); +} + +.datepicker-next:hover { + list-style-image: url("chrome://global/skin/arrow/arrow-rit-hov.gif"); +} + +.datepicker-previous[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif"); +} + +.datepicker-next[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif"); +} diff --git a/toolkit/themes/osx/global/dialog.css b/toolkit/themes/osx/global/dialog.css new file mode 100644 index 0000000000..98ed3ca207 --- /dev/null +++ b/toolkit/themes/osx/global/dialog.css @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +#commonDialog > image { + margin-inline-end: 14px !important; +} + +#commonDialog > .dialog-button-box { + margin-inline-start: 80px; +} + +dialog { + -moz-appearance: dialog; + padding: 14px; +} + +/* ::::: dialog buttons ::::: */ + +.dialog-button { + font: menu; +} + +/* ::::: dialog header ::::: */ + +dialogheader { + margin: 0 5px 5px; + padding: 5px 8px; +} + +.dialogheader-title { + margin: 0 !important; + font-size: larger; + font-weight: bold; + display: none; +} + +/* ::::: large dialog header ::::: */ + +.header-large { + -moz-box-orient: vertical; + margin: -14px -14px 0; + padding: 12px; + padding-inline-end: 5px; + padding-inline-start: 25px; +} + +.header-large > .dialogheader-title { + font: inherit; + font-weight: bold; +} + +.header-large > .dialogheader-description { + margin-left: 12px !important; +} + +.dialogheader-description { + font-weight: bold !important; +} + +.dialogheader-title { + font-weight: bold !important; +} + +/*XXX - belongs to toolkit/content/finddialog.xul: */ + +#findDialog, +#findDialog > menu, +#findDialog > groupbox { + font: menu !important; +} + +#dialog\.caseSensitive { + margin-top: 8px; +} diff --git a/toolkit/themes/osx/global/dirListing/dirListing.css b/toolkit/themes/osx/global/dirListing/dirListing.css new file mode 100644 index 0000000000..de881a5e4b --- /dev/null +++ b/toolkit/themes/osx/global/dirListing/dirListing.css @@ -0,0 +1,104 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +:root { + background-color: -moz-dialog; + color: -moz-dialogtext; + font: message-box; + padding-left: 2em; + padding-right: 2em; +} + +body { + border: 1px solid ThreeDShadow; + border-radius: 10px; + padding: 3em; + min-width: 30em; + max-width: 65em; + margin: 4em auto; + background-color: -moz-field; + color: -moz-fieldtext; +} + +h1 { + font-size: 160%; + margin: 0 0 .6em; + border-bottom: 1px solid ThreeDLightShadow; + font-weight: normal; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +p { + font-size: 110%; +} + +#UI_goUp { + margin-top: 0; + float: left; +} + +#UI_goUp:dir(rtl) { + float: right; +} + +#UI_showHidden { + margin-top: 0; + float: right; +} + +#UI_showHidden:dir(rtl) { + float: left; +} + +table { + clear: both; + width: 90%; + margin: 0 auto; +} + +thead { + font-size: 130%; +} + +/* last modified */ +th:last-child { + text-align: center; +} + +th:hover > a { + text-decoration: underline; +} + +body > table > tbody > tr:hover { + outline: 1px solid ThreeDLightShadow; + -moz-outline-radius: .3em; +} + +/* let 'Size' and 'Last Modified' take only as much space as they need and 'Name' all the rest */ +td:not(:first-child) { + width: 0; +} + +.up { + padding: 0 .5em; + margin-inline-start: 20px; +} + +.up::before { + margin-inline-end: 4px; + margin-inline-start: -20px; + vertical-align: middle; + content: url(chrome://global/skin/dirListing/up.png); +} + +.dir::before { + content: url(chrome://global/skin/dirListing/folder.png); +} diff --git a/toolkit/themes/osx/global/dirListing/folder.png b/toolkit/themes/osx/global/dirListing/folder.png new file mode 100644 index 0000000000..eb3a607e03 Binary files /dev/null and b/toolkit/themes/osx/global/dirListing/folder.png differ diff --git a/toolkit/themes/osx/global/dirListing/remote.png b/toolkit/themes/osx/global/dirListing/remote.png new file mode 100644 index 0000000000..d854bd9d9f Binary files /dev/null and b/toolkit/themes/osx/global/dirListing/remote.png differ diff --git a/toolkit/themes/osx/global/dirListing/up.png b/toolkit/themes/osx/global/dirListing/up.png new file mode 100644 index 0000000000..7af8949ad3 Binary files /dev/null and b/toolkit/themes/osx/global/dirListing/up.png differ diff --git a/toolkit/themes/osx/global/dropmarker.css b/toolkit/themes/osx/global/dropmarker.css new file mode 100644 index 0000000000..701eea75c4 --- /dev/null +++ b/toolkit/themes/osx/global/dropmarker.css @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +dropmarker { + -moz-appearance: menulist-button; + width: 16px; + -moz-box-align: center; + -moz-box-pack: center; + border: 2px solid; + -moz-border-top-colors: ThreeDLightShadow ThreeDHighlight; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDLightShadow ThreeDHighlight; + background-color: -moz-Dialog; + padding: 1px; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); + -moz-image-region: auto; +} + +dropmarker:hover:active:not([disabled="true"]) { + -moz-border-top-colors: ThreeDShadow ThreeDFace; + -moz-border-right-colors: ThreeDShadow ThreeDFace; + -moz-border-bottom-colors: ThreeDShadow ThreeDFace; + -moz-border-left-colors: ThreeDShadow ThreeDFace; + padding: 2px 0 0 2px; +} + +dropmarker[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); +} diff --git a/toolkit/themes/osx/global/filefield.css b/toolkit/themes/osx/global/filefield.css new file mode 100644 index 0000000000..8ae3fdb52a --- /dev/null +++ b/toolkit/themes/osx/global/filefield.css @@ -0,0 +1,38 @@ +/* +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +.fileFieldIcon { + width: 16px; + height: 16px; +} + +.fileFieldIcon[disabled="true"] { + opacity: 0.5; +} + +filefield { + margin: 4px; + margin-inline-start: 27px; + -moz-appearance: textfield; +} + +.fileFieldContentBox { + margin: -3px; + background-color: rgba(230, 230, 230, 0.6); + color: -moz-DialogText; + padding-top: 2px; + padding-bottom: 2px; + padding-inline-start: 5px; + padding-inline-end: 3px; +} + +.fileFieldLabel { + -moz-appearance: none; + background-color: transparent; + border: none; + margin: 0 4px; +} diff --git a/toolkit/themes/osx/global/filters.svg b/toolkit/themes/osx/global/filters.svg new file mode 100644 index 0000000000..d3ad6a76b8 --- /dev/null +++ b/toolkit/themes/osx/global/filters.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/toolkit/themes/osx/global/findBar.css b/toolkit/themes/osx/global/findBar.css new file mode 100644 index 0000000000..869a624322 --- /dev/null +++ b/toolkit/themes/osx/global/findBar.css @@ -0,0 +1,270 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include shared.inc +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +findbar { + background: @scopeBarBackground@; + border-top: @scopeBarSeparatorBorder@; + min-width: 1px; + padding: 4px 2px; + transition-property: margin-bottom, opacity, visibility; + transition-duration: 150ms, 150ms, 0s; + transition-timing-function: ease-in-out, ease-in-out, linear; +} + +findbar[hidden] { + /* Override display:none to make the transition work. */ + display: -moz-box; + visibility: collapse; + margin-bottom: -1em; + opacity: 0; + transition-delay: 0s, 0s, 150ms; +} + +findbar:-moz-lwtheme { + -moz-appearance: none; + background: none; + border-style: none; +} + +label.findbar-find-fast { + margin: 1px 3px 0 !important; + color: @scopeBarTitleColor@; + font-weight: bold; + text-shadow: @loweredShadow@; +} + +label.findbar-find-fast:-moz-lwtheme, +.findbar-find-status:-moz-lwtheme { + color: inherit; + text-shadow: inherit; +} + +.findbar-closebutton { + padding: 0; + margin: 0 4px; + border: none; +} + +.findbar-closebutton:-moz-lwtheme-brighttext { + list-style-image: url("chrome://global/skin/icons/close-inverted.png"); +} + +@media (min-resolution: 2dppx) { + .findbar-closebutton:-moz-lwtheme-brighttext { + list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png"); + } + + .findbar-closebutton > .toolbarbutton-icon { + width: 16px; + } +} + +.findbar-find-next, +.findbar-find-previous, +.findbar-highlight { + margin: 0 4px; + padding: 1px 3px; + -moz-appearance: none; + border-radius: 10000px; + border: @roundButtonBorder@; + background: @roundButtonBackground@; + box-shadow: @roundButtonShadow@; + color: buttontext; +} + +.findbar-container > toolbarbutton:-moz-focusring { + position: relative; + box-shadow: @focusRingShadow@, @roundButtonShadow@; +} + +.findbar-container > toolbarbutton > .toolbarbutton-text { + margin: 0 6px !important; +} + +.findbar-container > toolbarbutton[disabled] { + color: GrayText !important; +} + +.findbar-find-next:not([disabled]):hover:active, +.findbar-find-previous:not([disabled]):hover:active, +.findbar-highlight:not([disabled]):hover:active { + text-shadow: @loweredShadow@; + background: @roundButtonPressedBackground@; + box-shadow: @roundButtonPressedShadow@; +} + +.findbar-container > toolbarbutton:hover:active:-moz-focusring { + text-shadow: @loweredShadow@; + background: @roundButtonPressedBackground@; + box-shadow: @focusRingShadow@, @roundButtonPressedShadow@; +} + +.findbar-closebutton > .toolbarbutton-text { + display: none; +} + +/* Match case checkbox */ + +.findbar-container > checkbox { + list-style-image: url("chrome://global/skin/icons/checkbox.png"); + -moz-image-region: rect(0px 16px 16px 0px); + -moz-appearance: none; + margin: 0 2px; + -moz-margin-start: 7px; +} + +.findbar-container > checkbox:hover:active { + -moz-image-region: rect(0px 32px 16px 16px); +} +.findbar-container > checkbox[checked] { + -moz-image-region: rect(0px 48px 16px 32px); +} +.findbar-container > checkbox[checked]:hover:active { + -moz-image-region: rect(0px 64px 16px 48px); +} + +@media (min-resolution: 2dppx) { + .findbar-container > checkbox { + list-style-image: url("chrome://global/skin/icons/checkbox@2x.png"); + -moz-image-region: rect(0px 32px 32px 0px); + } + + .findbar-container > checkbox:hover:active { + -moz-image-region: rect(0px 64px 32px 32px); + } + .findbar-container > checkbox[checked] { + -moz-image-region: rect(0px 96px 32px 64px); + } + .findbar-container > checkbox[checked]:hover:active { + -moz-image-region: rect(0px 128px 32px 96px); + } +} + + + +.findbar-container > checkbox > .checkbox-check { + display: none; +} + +.findbar-container > checkbox > .checkbox-label-box > .checkbox-label { + margin: 0 !important; + padding: 2px 0 0; +} + +.findbar-container > checkbox > .checkbox-label-box > .checkbox-icon { + -moz-padding-start: 1px; + padding-bottom: 1px; +} +@media (min-resolution: 2dppx) { + .findbar-container > checkbox > .checkbox-label-box > .checkbox-icon { + width: 17px; + height: 17px; + } +} + +.findbar-container > checkbox:-moz-focusring > .checkbox-label-box > .checkbox-icon { + border-radius: 4px; + box-shadow: @focusRingShadow@; +} + +/* Search field */ + +.findbar-textbox { + -moz-appearance: none; + border-radius: 10000px; + border: none; + box-shadow: 0 1px 1.5px rgba(0, 0, 0, .7) inset, + 0 0 0 1px rgba(0, 0, 0, .17) inset; + background: url("chrome://global/skin/icons/search-textbox.png") -moz-Field no-repeat 5px center; + margin: 0 4px -1px; + padding: 3px 8px 2px; + -moz-padding-start: 19px; +} + +.findbar-textbox:not([focused="true"]):-moz-lwtheme { + opacity: 0.9; +} + +.findbar-textbox[focused="true"] { + box-shadow: @focusRingShadow@, + 0 1px 1.5px rgba(0, 0, 0, .8) inset; +} + +.findbar-textbox[flash="true"] { + background-color: #F7E379; + color: #000; +} + +.findbar-textbox[status="notfound"] { + background-color: #FD919B; + color: #FFF; +} + +/* find-next button */ + +.findbar-find-next { + -moz-border-end: none; + -moz-margin-end: 0 !important; +} + +.findbar-find-next:-moz-locale-dir(ltr), +.findbar-find-previous:-moz-locale-dir(rtl) { + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +/* find-previous button */ + +.findbar-find-previous { + -moz-margin-start: 0 !important; +} + +.findbar-find-previous:-moz-locale-dir(ltr), +.findbar-find-next:-moz-locale-dir(rtl) { + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; +} + +/* highlight button */ + +.findbar-highlight { + -moz-margin-start: 8px; +} + +.findbar-highlight > .toolbarbutton-icon { + width: 13px; + height: 8px; + margin: 0 4px; + -moz-margin-end: 0; + border: 1px solid #818181; + border-radius: 4px; + background-color: #F4F4F3; +} + + +.findbar-highlight[checked="true"] > .toolbarbutton-icon { + background-color: #FFFF00; + border-color: #818100; +} + +.find-status-icon { + display: none; +} + +.find-status-icon[status="pending"] { + display: block; + list-style-image: url("chrome://global/skin/icons/loading_16.png"); +} + +.findbar-find-status, +.found-matches { + color: #436599; + font-weight: bold; + text-shadow: 0 1px rgba(255, 255, 255, .4); + margin: 1px 1px 0 !important; + -moz-margin-start: 12px !important; +} diff --git a/toolkit/themes/osx/global/global.css b/toolkit/themes/osx/global/global.css new file mode 100644 index 0000000000..261abe3138 --- /dev/null +++ b/toolkit/themes/osx/global/global.css @@ -0,0 +1,378 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* all localizable skin settings shall live here */ +@import url("chrome://global/locale/intl.css"); + +%include shared.inc +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* ::::: XBL bindings ::::: */ + +menulist > menupopup { + -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars"); +} + +/* ::::: Variables ::::: */ +:root { + --arrowpanel-padding: 16px; + --arrowpanel-background: linear-gradient(hsla(0,0%,99%,1), hsla(0,0%,99%,.975) 10%, hsla(0,0%,98%,.975)); + --arrowpanel-color: hsl(0,0%,10%); + --arrowpanel-border-color: hsla(210,4%,10%,.05); + --arrowpanel-border-radius: 3.5px; +} + +/* ::::: root elements ::::: */ + +window, +page, +dialog, +wizard, +prefwindow { + -moz-appearance: dialog; + background-color: #FFFFFF; + color: -moz-DialogText; + font: message-box; +} + +prefwindow[type="child"] { + padding-top: 18px; + padding-bottom: 15px; + padding-inline-start: 18px; + padding-inline-end: 20px; +} + +/* deprecated */ +window.dialog { + padding-top: 8px; + padding-bottom: 10px; + padding-inline-start: 8px; + padding-inline-end: 10px; +} + +/* ::::: alert icons :::::*/ + +.message-icon, +.alert-icon, +.error-icon, +.question-icon { + width: 64px; + height: 64px; + margin: 6px; + margin-inline-end: 20px; +} + +.message-icon { + list-style-image: url("chrome://global/skin/icons/information-64.png"); +} + +.alert-dialog #info\.icon, +.alert-icon { + list-style-image: url("chrome://global/skin/icons/warning-64.png"); +} + +.error-icon { + list-style-image: url("chrome://global/skin/icons/error-64.png"); +} + +.question-icon { + list-style-image: url("chrome://global/skin/icons/question-64.png"); +} + +/* ::::: iframe ::::: */ + +iframe { + border: none; + width: 100px; + height: 100px; + min-width: 10px; + min-height: 10px; +} + +/* ::::: statusbar ::::: */ + +statusbar { + min-width: 1px; /* DON'T DELETE! + Prevents hiding of scrollbars in browser when window is made smaller.*/ + min-height: 15px !important; + margin: 0px !important; + /* need to use padding-inline-end when/if bug 631729 gets fixed: */ + padding: 0px 16px 1px 1px; + -moz-appearance: statusbar; + text-shadow: rgba(255, 255, 255, 0.4) 0 1px; +} + +statusbarpanel { + -moz-box-align: center; + -moz-box-pack: center; + padding: 0 4px; +} + +.statusbarpanel-iconic { + padding: 0px; +} + +/* ::::: miscellaneous formatting ::::: */ + +:root:-moz-lwtheme, +[lwthemefooter="true"] { + -moz-appearance: none; +} + +:root:-moz-lwtheme-darktext { + text-shadow: 0 -0.5px 1.5px white; +} + +:root:-moz-lwtheme-brighttext { + text-shadow: 1px 1px 1.5px black; +} + +statusbar:-moz-lwtheme { + -moz-appearance: none; + background: none; + border-style: none; + text-shadow: inherit; +} + +.inset { + border: 1px solid ThreeDShadow; + border-right-color: ThreeDHighlight; + border-bottom-color: ThreeDHighlight; + margin: 0 5px 5px; +} + +.outset { + border: 1px solid ThreeDShadow; + border-left-color: ThreeDHighlight; + border-top-color: ThreeDHighlight; +} + +separator:not([orient="vertical"]) { + height: 1.5em; +} +separator[orient="vertical"] { + width: 1.5em; +} + +separator.thin:not([orient="vertical"]) { + height: 0.5em; +} +separator.thin[orient="vertical"] { + width: 0.5em; +} + +separator.groove:not([orient="vertical"]) { + border-top: 1px solid #A3A3A3; + height: 0; + margin-top: 0.4em; + margin-bottom: 0.4em; +} +separator.groove[orient="vertical"] { + border-left: 1px solid #A3A3A3; + width: 0; + margin-left: 0.4em; + margin-right: 0.4em; +} + +.plain { + -moz-appearance: none; + margin: 0 !important; + border: none; + padding: 0; +} + +description, +label { + cursor: default; + margin-top: 1px; + margin-bottom: 2px; + margin-inline-start: 6px; + margin-inline-end: 5px; +} + +description { + margin-bottom: 4px; +} + +label[disabled="true"] { + color: GrayText; +} + +.tooltip-label { + margin: 0; +} + +.header { + font-weight: bold; +} + +.monospace { + font-family: monospace; +} + +.indent { + margin-inline-start: 23px; +} + +.box-padded { + padding: 5px; +} + +.spaced { + margin: 3px 5px 4px; +} + +.wizard-box { + padding: 20px 44px 10px; +} + +.text-link { + color: -moz-nativehyperlinktext; + cursor: pointer; +} + +.text-link:hover { + text-decoration: underline; +} + +.text-link:-moz-focusring { + box-shadow: @focusRingShadow@; +} + +.toolbar-focustarget { + -moz-user-focus: ignore !important; +} + +notification > button { + margin: 0 3px; + padding: 1px 10px; + min-width: 60px; + min-height: 16px; + -moz-appearance: none; + border-radius: 10000px; + border: @roundButtonBorder@; + text-shadow: @loweredShadow@; + background: @roundButtonBackground@; + box-shadow: @roundButtonShadow@; +} + +notification > button:active:hover { + background: @roundButtonPressedBackground@; + box-shadow: @roundButtonPressedShadow@; +} + +notification > button:-moz-focusring { + box-shadow: @focusRingShadow@, @roundButtonShadow@; +} + +notification > button:active:hover:-moz-focusring { + box-shadow: @focusRingShadow@, @roundButtonPressedShadow@; +} + +notification > button > .button-box > .button-text { + margin: 0 !important; +} + +popupnotificationcontent { + margin-top: .5em; +} + +/* :::::: autoscroll popup ::::: */ + +.autoscroller { + height: 28px; + width: 28px; + border: none; + margin: -14px; + padding: 0; + background-image: url("chrome://global/skin/icons/autoscroll.png"); + background-color: transparent; + background-position: right top; + -moz-appearance: none; + -moz-window-shadow: none; +} + +.autoscroller[scrolldir="NS"] { + background-position: right center; +} + +.autoscroller[scrolldir="EW"] { + background-position: right bottom; +} + +/* autorepeatbuttons in menus */ + +.popup-internal-box > autorepeatbutton { + height: 15px; + position: relative; + list-style-image: none; + /* Here we're using a little magic. + * The arrow button is supposed to overlay the scrollbox, blocking + * everything under it from reaching the screen. However, the menu background + * is slightly transparent, so how can we block something completely without + * messing up the transparency? It's easy: The native theming of the + * "menuitem" appearance uses CGContextClearRect before drawing, which + * clears everything under it. + * Without help from native theming this effect wouldn't be achievable. + */ + -moz-appearance: menuitem; +} + +.popup-internal-box > .autorepeatbutton-up { + padding-top: 1px; /* 4px padding-top from the .popup-internal-box. */ + margin-bottom: -15px; +} + +.popup-internal-box > .autorepeatbutton-up > .autorepeatbutton-icon { + -moz-appearance: button-arrow-up; +} + +.popup-internal-box > .autorepeatbutton-down { + padding-top: 5px; + margin-top: -15px; +} + +.popup-internal-box > .autorepeatbutton-down > .autorepeatbutton-icon { + -moz-appearance: button-arrow-down; +} + +.popup-internal-box > autorepeatbutton[disabled="true"] { + visibility: collapse; +} + +/* :::::: Close button icons ::::: */ + +.close-icon { + list-style-image: url("chrome://global/skin/icons/close.png"); + -moz-image-region: rect(0, 16px, 16px, 0); +} + +.close-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +.close-icon:hover:active { + -moz-image-region: rect(0, 48px, 16px, 32px); +} + +@media (min-resolution: 2dppx) { + .close-icon > .button-icon, + .close-icon > .button-box > .button-icon, + .close-icon > .toolbarbutton-icon { + width: 16px; + } + + .close-icon { + list-style-image: url("chrome://global/skin/icons/close@2x.png"); + -moz-image-region: rect(0, 32px, 32px, 0); + } + + .close-icon:hover { + -moz-image-region: rect(0, 64px, 32px, 32px); + } + + .close-icon:hover:active { + -moz-image-region: rect(0, 96px, 32px, 64px); + } +} diff --git a/toolkit/themes/osx/global/groupbox.css b/toolkit/themes/osx/global/groupbox.css new file mode 100644 index 0000000000..8406458278 --- /dev/null +++ b/toolkit/themes/osx/global/groupbox.css @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +groupbox { + padding: 5px 1px 1px; + padding-inline-start: 0; + margin: 6px; +} + +.groupbox-body { + -moz-appearance: groupbox; + padding: 8px 8px 3px; + margin: 0; +} + +caption { + padding-inline-start: 4px; + padding-bottom: 1px; + font: caption; +} + +/* !important is needed to override label in global.css */ +.caption-text { + margin-top: 0 !important; + margin-bottom: 0 !important; + margin-inline-start: 1px !important; +} diff --git a/toolkit/themes/osx/global/icons/Error.png b/toolkit/themes/osx/global/icons/Error.png new file mode 100644 index 0000000000..424ebfd4ad Binary files /dev/null and b/toolkit/themes/osx/global/icons/Error.png differ diff --git a/toolkit/themes/osx/global/icons/autocomplete-dropmarker.png b/toolkit/themes/osx/global/icons/autocomplete-dropmarker.png new file mode 100644 index 0000000000..e48d044526 Binary files /dev/null and b/toolkit/themes/osx/global/icons/autocomplete-dropmarker.png differ diff --git a/toolkit/themes/osx/global/icons/autocomplete-search.svg b/toolkit/themes/osx/global/icons/autocomplete-search.svg new file mode 100644 index 0000000000..3d1795d29d --- /dev/null +++ b/toolkit/themes/osx/global/icons/autocomplete-search.svg @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/toolkit/themes/osx/global/icons/autoscroll.png b/toolkit/themes/osx/global/icons/autoscroll.png new file mode 100644 index 0000000000..c21e067d9a Binary files /dev/null and b/toolkit/themes/osx/global/icons/autoscroll.png differ diff --git a/toolkit/themes/osx/global/icons/blacklist_64.png b/toolkit/themes/osx/global/icons/blacklist_64.png new file mode 100644 index 0000000000..90555a93bf Binary files /dev/null and b/toolkit/themes/osx/global/icons/blacklist_64.png differ diff --git a/toolkit/themes/osx/global/icons/blacklist_favicon.png b/toolkit/themes/osx/global/icons/blacklist_favicon.png new file mode 100644 index 0000000000..e67d3d34f0 Binary files /dev/null and b/toolkit/themes/osx/global/icons/blacklist_favicon.png differ diff --git a/toolkit/themes/osx/global/icons/checkbox.png b/toolkit/themes/osx/global/icons/checkbox.png new file mode 100644 index 0000000000..137e4e801f Binary files /dev/null and b/toolkit/themes/osx/global/icons/checkbox.png differ diff --git a/toolkit/themes/osx/global/icons/checkbox@2x.png b/toolkit/themes/osx/global/icons/checkbox@2x.png new file mode 100644 index 0000000000..61bcc59c7d Binary files /dev/null and b/toolkit/themes/osx/global/icons/checkbox@2x.png differ diff --git a/toolkit/themes/osx/global/icons/chevron-inverted.png b/toolkit/themes/osx/global/icons/chevron-inverted.png new file mode 100644 index 0000000000..8ad164baaf Binary files /dev/null and b/toolkit/themes/osx/global/icons/chevron-inverted.png differ diff --git a/toolkit/themes/osx/global/icons/chevron-inverted@2x.png b/toolkit/themes/osx/global/icons/chevron-inverted@2x.png new file mode 100644 index 0000000000..4327a1a457 Binary files /dev/null and b/toolkit/themes/osx/global/icons/chevron-inverted@2x.png differ diff --git a/toolkit/themes/osx/global/icons/chevron.png b/toolkit/themes/osx/global/icons/chevron.png new file mode 100644 index 0000000000..b2d31e38f5 Binary files /dev/null and b/toolkit/themes/osx/global/icons/chevron.png differ diff --git a/toolkit/themes/osx/global/icons/chevron@2x.png b/toolkit/themes/osx/global/icons/chevron@2x.png new file mode 100644 index 0000000000..dd91178030 Binary files /dev/null and b/toolkit/themes/osx/global/icons/chevron@2x.png differ diff --git a/toolkit/themes/osx/global/icons/close.png b/toolkit/themes/osx/global/icons/close.png new file mode 100644 index 0000000000..9bba044ce5 Binary files /dev/null and b/toolkit/themes/osx/global/icons/close.png differ diff --git a/toolkit/themes/osx/global/icons/close@2x.png b/toolkit/themes/osx/global/icons/close@2x.png new file mode 100755 index 0000000000..01c5ef4232 Binary files /dev/null and b/toolkit/themes/osx/global/icons/close@2x.png differ diff --git a/toolkit/themes/osx/global/icons/error-16.png b/toolkit/themes/osx/global/icons/error-16.png new file mode 100644 index 0000000000..41514d0806 Binary files /dev/null and b/toolkit/themes/osx/global/icons/error-16.png differ diff --git a/toolkit/themes/osx/global/icons/error-64.png b/toolkit/themes/osx/global/icons/error-64.png new file mode 100644 index 0000000000..972abaff3b Binary files /dev/null and b/toolkit/themes/osx/global/icons/error-64.png differ diff --git a/toolkit/themes/osx/global/icons/error-large.png b/toolkit/themes/osx/global/icons/error-large.png new file mode 100644 index 0000000000..5a1479e28b Binary files /dev/null and b/toolkit/themes/osx/global/icons/error-large.png differ diff --git a/toolkit/themes/osx/global/icons/glyph-dropdown.png b/toolkit/themes/osx/global/icons/glyph-dropdown.png new file mode 100644 index 0000000000..fa08515836 Binary files /dev/null and b/toolkit/themes/osx/global/icons/glyph-dropdown.png differ diff --git a/toolkit/themes/osx/global/icons/glyph-dropdown@2x.png b/toolkit/themes/osx/global/icons/glyph-dropdown@2x.png new file mode 100644 index 0000000000..653039a3e6 Binary files /dev/null and b/toolkit/themes/osx/global/icons/glyph-dropdown@2x.png differ diff --git a/toolkit/themes/osx/global/icons/information-16.png b/toolkit/themes/osx/global/icons/information-16.png new file mode 100644 index 0000000000..6fb2e3a804 Binary files /dev/null and b/toolkit/themes/osx/global/icons/information-16.png differ diff --git a/toolkit/themes/osx/global/icons/information-24.png b/toolkit/themes/osx/global/icons/information-24.png new file mode 100644 index 0000000000..6907d02e5f Binary files /dev/null and b/toolkit/themes/osx/global/icons/information-24.png differ diff --git a/toolkit/themes/osx/global/icons/information-32.png b/toolkit/themes/osx/global/icons/information-32.png new file mode 100644 index 0000000000..4501bc813a Binary files /dev/null and b/toolkit/themes/osx/global/icons/information-32.png differ diff --git a/toolkit/themes/osx/global/icons/information-64.png b/toolkit/themes/osx/global/icons/information-64.png new file mode 100644 index 0000000000..8d9b72498e Binary files /dev/null and b/toolkit/themes/osx/global/icons/information-64.png differ diff --git a/toolkit/themes/osx/global/icons/information-large.png b/toolkit/themes/osx/global/icons/information-large.png new file mode 100644 index 0000000000..3912f1c79a Binary files /dev/null and b/toolkit/themes/osx/global/icons/information-large.png differ diff --git a/toolkit/themes/osx/global/icons/loading_16.png b/toolkit/themes/osx/global/icons/loading_16.png new file mode 100644 index 0000000000..1b2df8093d Binary files /dev/null and b/toolkit/themes/osx/global/icons/loading_16.png differ diff --git a/toolkit/themes/osx/global/icons/menulist-dropmarker.png b/toolkit/themes/osx/global/icons/menulist-dropmarker.png new file mode 100644 index 0000000000..689a1fe877 Binary files /dev/null and b/toolkit/themes/osx/global/icons/menulist-dropmarker.png differ diff --git a/toolkit/themes/osx/global/icons/notfound.png b/toolkit/themes/osx/global/icons/notfound.png new file mode 100644 index 0000000000..694dae910e Binary files /dev/null and b/toolkit/themes/osx/global/icons/notfound.png differ diff --git a/toolkit/themes/osx/global/icons/notloading_16.png b/toolkit/themes/osx/global/icons/notloading_16.png new file mode 100644 index 0000000000..ece0ee18a1 Binary files /dev/null and b/toolkit/themes/osx/global/icons/notloading_16.png differ diff --git a/toolkit/themes/osx/global/icons/panebutton-active.png b/toolkit/themes/osx/global/icons/panebutton-active.png new file mode 100644 index 0000000000..ca241c7b8a Binary files /dev/null and b/toolkit/themes/osx/global/icons/panebutton-active.png differ diff --git a/toolkit/themes/osx/global/icons/panebutton-inactive.png b/toolkit/themes/osx/global/icons/panebutton-inactive.png new file mode 100644 index 0000000000..de527b6627 Binary files /dev/null and b/toolkit/themes/osx/global/icons/panebutton-inactive.png differ diff --git a/toolkit/themes/osx/global/icons/panel-dropmarker.png b/toolkit/themes/osx/global/icons/panel-dropmarker.png new file mode 100644 index 0000000000..e605e835c7 Binary files /dev/null and b/toolkit/themes/osx/global/icons/panel-dropmarker.png differ diff --git a/toolkit/themes/osx/global/icons/question-16.png b/toolkit/themes/osx/global/icons/question-16.png new file mode 100644 index 0000000000..8d8311fced Binary files /dev/null and b/toolkit/themes/osx/global/icons/question-16.png differ diff --git a/toolkit/themes/osx/global/icons/question-32.png b/toolkit/themes/osx/global/icons/question-32.png new file mode 100644 index 0000000000..7c80831b04 Binary files /dev/null and b/toolkit/themes/osx/global/icons/question-32.png differ diff --git a/toolkit/themes/osx/global/icons/question-64.png b/toolkit/themes/osx/global/icons/question-64.png new file mode 100644 index 0000000000..96fd746409 Binary files /dev/null and b/toolkit/themes/osx/global/icons/question-64.png differ diff --git a/toolkit/themes/osx/global/icons/question-large.png b/toolkit/themes/osx/global/icons/question-large.png new file mode 100644 index 0000000000..dd2b21874b Binary files /dev/null and b/toolkit/themes/osx/global/icons/question-large.png differ diff --git a/toolkit/themes/osx/global/icons/resizer-rtl.png b/toolkit/themes/osx/global/icons/resizer-rtl.png new file mode 100644 index 0000000000..6ab7d33457 Binary files /dev/null and b/toolkit/themes/osx/global/icons/resizer-rtl.png differ diff --git a/toolkit/themes/osx/global/icons/resizer-rtl@2x.png b/toolkit/themes/osx/global/icons/resizer-rtl@2x.png new file mode 100644 index 0000000000..6c85d4f332 Binary files /dev/null and b/toolkit/themes/osx/global/icons/resizer-rtl@2x.png differ diff --git a/toolkit/themes/osx/global/icons/resizer.png b/toolkit/themes/osx/global/icons/resizer.png new file mode 100644 index 0000000000..efed0240b8 Binary files /dev/null and b/toolkit/themes/osx/global/icons/resizer.png differ diff --git a/toolkit/themes/osx/global/icons/resizer@2x.png b/toolkit/themes/osx/global/icons/resizer@2x.png new file mode 100644 index 0000000000..2304cc65fe Binary files /dev/null and b/toolkit/themes/osx/global/icons/resizer@2x.png differ diff --git a/toolkit/themes/osx/global/icons/search-textbox.svg b/toolkit/themes/osx/global/icons/search-textbox.svg new file mode 100644 index 0000000000..12be833c40 --- /dev/null +++ b/toolkit/themes/osx/global/icons/search-textbox.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/toolkit/themes/osx/global/icons/searchfield-cancel.svg b/toolkit/themes/osx/global/icons/searchfield-cancel.svg new file mode 100644 index 0000000000..9899144e95 --- /dev/null +++ b/toolkit/themes/osx/global/icons/searchfield-cancel.svg @@ -0,0 +1,20 @@ + + + + + + + + + \ No newline at end of file diff --git a/toolkit/themes/osx/global/icons/sslWarning.png b/toolkit/themes/osx/global/icons/sslWarning.png new file mode 100644 index 0000000000..e8ad586b6e Binary files /dev/null and b/toolkit/themes/osx/global/icons/sslWarning.png differ diff --git a/toolkit/themes/osx/global/icons/tabprompts-bgtexture.png b/toolkit/themes/osx/global/icons/tabprompts-bgtexture.png new file mode 100644 index 0000000000..caffc241cf Binary files /dev/null and b/toolkit/themes/osx/global/icons/tabprompts-bgtexture.png differ diff --git a/toolkit/themes/osx/global/icons/warning-16.png b/toolkit/themes/osx/global/icons/warning-16.png new file mode 100644 index 0000000000..2ab4b3915e Binary files /dev/null and b/toolkit/themes/osx/global/icons/warning-16.png differ diff --git a/toolkit/themes/osx/global/icons/warning-32.png b/toolkit/themes/osx/global/icons/warning-32.png new file mode 100644 index 0000000000..750abaa220 Binary files /dev/null and b/toolkit/themes/osx/global/icons/warning-32.png differ diff --git a/toolkit/themes/osx/global/icons/warning-64.png b/toolkit/themes/osx/global/icons/warning-64.png new file mode 100644 index 0000000000..37d2120538 Binary files /dev/null and b/toolkit/themes/osx/global/icons/warning-64.png differ diff --git a/toolkit/themes/osx/global/icons/warning-large.png b/toolkit/themes/osx/global/icons/warning-large.png new file mode 100644 index 0000000000..73fd65f6fa Binary files /dev/null and b/toolkit/themes/osx/global/icons/warning-large.png differ diff --git a/toolkit/themes/osx/global/in-content/common.css b/toolkit/themes/osx/global/in-content/common.css new file mode 100644 index 0000000000..a987cbfe1f --- /dev/null +++ b/toolkit/themes/osx/global/in-content/common.css @@ -0,0 +1,121 @@ +/* - This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this file, + - You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../shared.inc +%include ../../../shared/in-content/common.inc.css + +xul|tabs { + padding-right: 0; + padding-left: 0; +} + +xul|tab[visuallyselected] { + text-shadow: none; +} + +xul|button, +html|button, +xul|colorpicker[type="button"], +xul|menulist { + margin-top: 3px; +} + +xul|button, +html|button { + /* use the same margin of other elements for the alignment */ + margin-left: 4px; + margin-right: 4px; +} + +xul|caption { + padding-inline-start: 0; +} + +xul|groupbox > xul|*.groupbox-body { + padding: 0; +} + +xul|menulist:not([editable="true"]) > xul|menupopup > xul|menuitem[checked="true"]::before, +xul|menulist:not([editable="true"]) > xul|menupopup > xul|menuitem[selected="true"]::before { + display: none; +} + +xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker { + display: -moz-box; + margin-top: 1px; + margin-bottom: 1px; +} + +xul|menulist > xul|menupopup xul|menu, +xul|menulist > xul|menupopup xul|menuitem, +xul|button[type="menu"] > xul|menupopup xul|menu, +xul|button[type="menu"] > xul|menupopup xul|menuitem { + padding-inline-end: 34px; +} + +xul|*.help-button > xul|*.button-box > xul|*.button-icon { + margin-inline-start: 0; +} + +xul|*.checkbox-icon { + margin-right: 0; +} + +xul|*.radio-icon { + margin-inline-end: 0; +} + +xul|*.numberbox-input-box { + -moz-appearance: none; + border-width: 0; +} + +xul|description { + font-size: 1.25rem; + line-height: 22px; +} + +xul|*.text-link:-moz-focusring { + color: var(--in-content-link-highlight); + text-decoration: underline; + box-shadow: none; +} + +xul|button:-moz-focusring, +xul|menulist:-moz-focusring, +xul|checkbox:-moz-focusring > .checkbox-check, +html|input[type="checkbox"]:-moz-focusring + html|label:before, +xul|radio[focused="true"] > .radio-check, +xul|tab:-moz-focusring > .tab-middle > .tab-text { + outline: 2px solid rgba(0,149,221,0.5); + outline-offset: 1px; + -moz-outline-radius: 2px; +} + +xul|radio[focused="true"] > .radio-check { + -moz-outline-radius: 100%; +} + +xul|spinbuttons { + -moz-appearance: none; +} + +xul|*.spinbuttons-up { + margin-top: 0 !important; + border-radius: 4px 4px 0 0; +} + +xul|*.spinbuttons-down { + margin-bottom: 0 !important; + border-radius: 0 0 4px 4px; +} + +xul|*.spinbuttons-button > xul|*.button-box { + padding-inline-start: 2px !important; + padding-inline-end: 3px !important; +} + +xul|*.spinbuttons-button > xul|*.button-box > xul|*.button-text { + display: none; +} diff --git a/toolkit/themes/osx/global/in-content/info-pages.css b/toolkit/themes/osx/global/in-content/info-pages.css new file mode 100644 index 0000000000..a25b9f6a3d --- /dev/null +++ b/toolkit/themes/osx/global/in-content/info-pages.css @@ -0,0 +1 @@ +%include ../../../shared/in-content/info-pages.inc.css \ No newline at end of file diff --git a/toolkit/themes/osx/global/inContentUI.css b/toolkit/themes/osx/global/inContentUI.css new file mode 100644 index 0000000000..17e2e6ae33 --- /dev/null +++ b/toolkit/themes/osx/global/inContentUI.css @@ -0,0 +1,144 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include shared.inc + +/* + * The default namespace for this file is XUL. Be sure to prefix rules that + * are applicable to both XUL and HTML with '*|'. + */ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +/* Page background */ +*|*:root { + -moz-appearance: none; + padding: 18px; + background-image: /* Texture */ + url("chrome://global/skin/inContentUI/background-texture.png"), + /* Gradient */ + linear-gradient(#ADB5C2, #BFC6D1); +} + +/* Use the new in-content colors for #contentAreaDownloadsView. After landing + of bug 989469 the colors can be moved to *|*:root */ +*|*#contentAreaDownloadsView { + background: #f1f1f1; + color: #424e5a; +} + +html|html { + font: message-box; +} + +/* Content */ +*|*.main-content { + /* Needed to allow the radius to clip the inner content, see bug 595656 */ + overflow: hidden; + background-image: linear-gradient(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.25) 50%, rgba(255, 255, 255, 0.05)); + border: 1px solid rgba(50, 65, 92, 0.4); + border-radius: 5px; +} + +/* Buttons */ +*|button, +menulist, +colorpicker[type="button"] { + -moz-appearance: none; + padding: 1px 4px; + min-width: 60px; + border-radius: 3px; + border: 1px solid rgba(60,73,97,0.5); + box-shadow: inset 0 1px rgba(255,255,255,0.25), 0 1px rgba(255,255,255,0.25); + background-color: transparent; + background-image: linear-gradient(rgba(255,255,255,0.45), rgba(255,255,255,0.2)); + background-clip: padding-box; + color: #252F3B; + text-shadow: @loweredShadow@; +} + +button:-moz-focusring > .button-box, +menulist:-moz-focusring:not([open="true"]) > .menulist-label-box, +colorpicker[type="button"]:-moz-focusring:not([open="true"]) > .colorpicker-button-colorbox { + outline: 1px dotted #252F3B; +} + +html|button[disabled], +button[disabled="true"], +menulist[disabled="true"], +colorpicker[type="button"][disabled="true"] { + opacity: 0.8; + color: #505050; +} + +html|button:not([disabled]):active:hover, +button:not([disabled="true"]):active:hover, +menulist[open="true"]:not([disabled="true"]), +colorpicker[type="button"][open="true"]:not([disabled="true"]) { + box-shadow: inset 0 1px 3px rgba(0,0,0,.2), 0 1px rgba(255,255,255,0.25); + background-image: linear-gradient(rgba(45,54,71,0.3), rgba(45,54,71,0.1)); + border-color: rgba(60,73,97,0.7); +} + +menulist { + -moz-padding-end: 0; + margin-left: 5px; + margin-right: 5px; +} + +/* Tweak margins so the focus ring is in the right place. */ +menulist > .menulist-label-box { + -moz-margin-end: 3px; + margin-top: 1px; +} + +menulist > .menulist-label-box > .menulist-label { + margin-top: 0px !important; + margin-bottom: 0px !important; +} + +menulist > .menulist-dropmarker { + -moz-appearance: none; + display: -moz-box; + background: transparent; + border: none; + -moz-border-start: 1px solid rgba(60,73,97,0.5); + margin-top: -1px; + margin-bottom: -1px; +} + +colorpicker[type="button"] { + margin: 1px 5px 2px 5px; + padding: 3px; + height: 25px; +} + +spinbuttons { + -moz-appearance: none; +} + +spinbuttons > .spinbuttons-box > .spinbuttons-button { + min-width: 12px; +} + +.spinbuttons-button > .button-box > .button-text { + display: none; +} + +.spinbuttons-button[disabled="true"] > .button-box > .button-icon { + opacity: 0.5; +} + +spinbuttons > .spinbuttons-box > .spinbuttons-up { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); + border-bottom-width: 0; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +spinbuttons > .spinbuttons-box > .spinbuttons-down { + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn new file mode 100644 index 0000000000..9ca73cc6bc --- /dev/null +++ b/toolkit/themes/osx/global/jar.mn @@ -0,0 +1,156 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include ../../shared/jar.inc.mn + +toolkit.jar: + skin/classic/global/10pct_transparent_grey.png + skin/classic/global/50pct_transparent_grey.png + skin/classic/global/arrow.css + skin/classic/global/autocomplete.css + skin/classic/global/button.css + skin/classic/global/checkbox.css + skin/classic/global/colorpicker.css + skin/classic/global/commonDialog.css + skin/classic/global/customizeToolbar.css + skin/classic/global/dialog.css + skin/classic/global/dropmarker.css + skin/classic/global/filefield.css + skin/classic/global/filters.svg +* skin/classic/global/findBar.css +* skin/classic/global/global.css + skin/classic/global/groupbox.css +* skin/classic/global/inContentUI.css + skin/classic/global/linkTree.css + skin/classic/global/listbox.css + skin/classic/global/menu.css + skin/classic/global/menulist.css +* skin/classic/global/notification.css + skin/classic/global/netError.css + skin/classic/global/numberbox.css + skin/classic/global/popup.css + skin/classic/global/preferences.css + skin/classic/global/progressmeter.css + skin/classic/global/radio.css + skin/classic/global/resizer.css + skin/classic/global/richlistbox.css + skin/classic/global/scrollbars.css (nativescrollbars.css) + skin/classic/global/scale.css + skin/classic/global/scrollbox.css + skin/classic/global/spinbuttons.css + skin/classic/global/splitter.css + skin/classic/global/tabprompts.css + skin/classic/global/tabbox.css + skin/classic/global/textbox.css + skin/classic/global/datetimepicker.css +* skin/classic/global/toolbar.css + skin/classic/global/toolbarbutton.css +* skin/classic/global/tree.css +* skin/classic/global/viewbuttons.css + skin/classic/global/wizard.css + skin/classic/global/alerts/alert.css (alerts/alert.css) + skin/classic/global/arrow/arrow-dn-dis.gif (arrow/arrow-dn-dis.gif) + skin/classic/global/arrow/arrow-dn-dis.png (arrow/arrow-dn-dis.png) + skin/classic/global/arrow/arrow-dn-sharp.gif (arrow/arrow-dn-sharp.gif) + skin/classic/global/arrow/arrow-dn.gif (arrow/arrow-dn.gif) + skin/classic/global/arrow/arrow-dn.png (arrow/arrow-dn.png) + skin/classic/global/arrow/arrow-lft-dis.gif (arrow/arrow-lft-dis.gif) + skin/classic/global/arrow/arrow-lft-hov.gif (arrow/arrow-lft-hov.gif) + skin/classic/global/arrow/arrow-lft-sharp-end.gif (arrow/arrow-lft-sharp-end.gif) + skin/classic/global/arrow/arrow-lft-sharp.gif (arrow/arrow-lft-sharp.gif) + skin/classic/global/arrow/arrow-lft.gif (arrow/arrow-lft.gif) + skin/classic/global/arrow/arrow-rit-dis.gif (arrow/arrow-rit-dis.gif) + skin/classic/global/arrow/arrow-rit-hov.gif (arrow/arrow-rit-hov.gif) + skin/classic/global/arrow/arrow-rit-sharp-end.gif (arrow/arrow-rit-sharp-end.gif) + skin/classic/global/arrow/arrow-rit-sharp.gif (arrow/arrow-rit-sharp.gif) + skin/classic/global/arrow/arrow-rit.gif (arrow/arrow-rit.gif) + skin/classic/global/arrow/arrow-up-dis.gif (arrow/arrow-up-dis.gif) + skin/classic/global/arrow/arrow-up-sharp.gif (arrow/arrow-up-sharp.gif) + skin/classic/global/arrow/arrow-up.gif (arrow/arrow-up.gif) + skin/classic/global/arrow/panelarrow-horizontal.png (arrow/panelarrow-horizontal.png) + skin/classic/global/arrow/panelarrow-horizontal@2x.png (arrow/panelarrow-horizontal@2x.png) + skin/classic/global/arrow/panelarrow-vertical.png (arrow/panelarrow-vertical.png) + skin/classic/global/arrow/panelarrow-vertical@2x.png (arrow/panelarrow-vertical@2x.png) + skin/classic/global/checkbox/cbox-check.gif (checkbox/cbox-check.gif) + skin/classic/global/checkbox/cbox-check-dis.gif (checkbox/cbox-check-dis.gif) + skin/classic/global/console/console-error-caret.gif (console/console-error-caret.gif) + skin/classic/global/console/console-error-dash.gif (console/console-error-dash.gif) +* skin/classic/global/console/console.css (console/console.css) + skin/classic/global/dirListing/dirListing.css (dirListing/dirListing.css) + skin/classic/global/dirListing/folder.png (dirListing/folder.png) + skin/classic/global/dirListing/remote.png (dirListing/remote.png) + skin/classic/global/dirListing/up.png (dirListing/up.png) + skin/classic/global/icons/autocomplete-dropmarker.png (icons/autocomplete-dropmarker.png) + skin/classic/global/icons/autocomplete-search.svg (icons/autocomplete-search.svg) + skin/classic/global/icons/autoscroll.png (icons/autoscroll.png) + skin/classic/global/icons/blacklist_favicon.png (icons/blacklist_favicon.png) + skin/classic/global/icons/blacklist_64.png (icons/blacklist_64.png) + skin/classic/global/icons/chevron.png (icons/chevron.png) + skin/classic/global/icons/chevron-inverted.png (icons/chevron-inverted.png) + skin/classic/global/icons/chevron@2x.png (icons/chevron@2x.png) + skin/classic/global/icons/chevron-inverted@2x.png (icons/chevron-inverted@2x.png) + skin/classic/global/icons/checkbox.png (icons/checkbox.png) + skin/classic/global/icons/checkbox@2x.png (icons/checkbox@2x.png) + skin/classic/global/icons/close.png (icons/close.png) + skin/classic/global/icons/close@2x.png (icons/close@2x.png) + skin/classic/global/icons/glyph-dropdown.png (icons/glyph-dropdown.png) + skin/classic/global/icons/glyph-dropdown@2x.png (icons/glyph-dropdown@2x.png) + skin/classic/global/icons/information-16.png (icons/information-16.png) + skin/classic/global/icons/information-24.png (icons/information-24.png) + skin/classic/global/icons/information-32.png (icons/information-32.png) + skin/classic/global/icons/information-64.png (icons/information-64.png) + skin/classic/global/icons/information-large.png (icons/information-large.png) + skin/classic/global/icons/loading_16.png (icons/loading_16.png) + skin/classic/global/icons/menulist-dropmarker.png (icons/menulist-dropmarker.png) + skin/classic/global/icons/notfound.png (icons/notfound.png) + skin/classic/global/icons/notloading_16.png (icons/notloading_16.png) + skin/classic/global/icons/panebutton-active.png (icons/panebutton-active.png) + skin/classic/global/icons/panebutton-inactive.png (icons/panebutton-inactive.png) + skin/classic/global/icons/panel-dropmarker.png (icons/panel-dropmarker.png) + skin/classic/global/icons/resizer.png (icons/resizer.png) + skin/classic/global/icons/resizer@2x.png (icons/resizer@2x.png) + skin/classic/global/icons/resizer-rtl.png (icons/resizer-rtl.png) + skin/classic/global/icons/resizer-rtl@2x.png (icons/resizer-rtl@2x.png) + skin/classic/global/icons/search-textbox.svg (icons/search-textbox.svg) + skin/classic/global/icons/searchfield-cancel.svg (icons/searchfield-cancel.svg) + skin/classic/global/icons/tabprompts-bgtexture.png (icons/tabprompts-bgtexture.png) + skin/classic/global/icons/warning-16.png (icons/warning-16.png) + skin/classic/global/icons/warning-32.png (icons/warning-32.png) + skin/classic/global/icons/warning-64.png (icons/warning-64.png) + skin/classic/global/icons/warning-large.png (icons/warning-large.png) + skin/classic/global/icons/error-16.png (icons/error-16.png) + skin/classic/global/icons/error-64.png (icons/error-64.png) + skin/classic/global/icons/error-large.png (icons/error-large.png) + skin/classic/global/icons/Error.png (icons/Error.png) + skin/classic/global/icons/question-16.png (icons/question-16.png) + skin/classic/global/icons/question-32.png (icons/question-32.png) + skin/classic/global/icons/question-64.png (icons/question-64.png) + skin/classic/global/icons/question-large.png (icons/question-large.png) + skin/classic/global/icons/sslWarning.png (icons/sslWarning.png) + skin/classic/global/notification/close.png (notification/close.png) + skin/classic/global/notification/error-icon.png (notification/error-icon.png) + skin/classic/global/notification/info-icon.png (notification/info-icon.png) + skin/classic/global/notification/warning-icon.png (notification/warning-icon.png) +* skin/classic/global/in-content/common.css (in-content/common.css) +* skin/classic/global/in-content/info-pages.css (in-content/info-pages.css) + skin/classic/global/scale/scale-tray-horiz.gif (scale/scale-tray-horiz.gif) + skin/classic/global/scale/scale-tray-vert.gif (scale/scale-tray-vert.gif) + skin/classic/global/splitter/dimple.png (splitter/dimple.png) + skin/classic/global/splitter/grip-bottom.gif (splitter/grip-bottom.gif) + skin/classic/global/splitter/grip-top.gif (splitter/grip-top.gif) + skin/classic/global/splitter/grip-left.gif (splitter/grip-left.gif) + skin/classic/global/splitter/grip-right.gif (splitter/grip-right.gif) + skin/classic/global/toolbar/spring.png (toolbar/spring.png) + skin/classic/global/toolbar/toolbar-separator.png (toolbar/toolbar-separator.png) + skin/classic/global/tree/arrow-disclosure.svg (tree/arrow-disclosure.svg) + skin/classic/global/tree/columnpicker.gif (tree/columnpicker.gif) + skin/classic/global/tree/folder.png (tree/folder.png) + skin/classic/global/tree/folder@2x.png (tree/folder@2x.png) + +#ifdef MOZ_PHOENIX +[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: +#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES +[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: +#endif +% override chrome://global/skin/dirListing/local.png chrome://global/skin/dirListing/folder.png diff --git a/toolkit/themes/osx/global/linkTree.css b/toolkit/themes/osx/global/linkTree.css new file mode 100644 index 0000000000..d83c5bfd9d --- /dev/null +++ b/toolkit/themes/osx/global/linkTree.css @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/** + * All the properties in this rule are important to avoid having to create + * a special type of tree. This stylesheet can be loaded into a document with + * a single tree that is a link tree. Hardly elegant but it's efficient. + */ +treeitem[selected="true"] > treerow + { + background : transparent !important; + border : none !important; + color : -moz-FieldText !important; + } + +treecell:hover + { + text-decoration : underline !important; + color : #000080 !important; + cursor : pointer; + } + +treecell:hover:active + { + text-decoration : underline !important; + color : red !important; + } + + diff --git a/toolkit/themes/osx/global/listbox.css b/toolkit/themes/osx/global/listbox.css new file mode 100644 index 0000000000..90928c7699 --- /dev/null +++ b/toolkit/themes/osx/global/listbox.css @@ -0,0 +1,113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +listbox { + -moz-appearance: listbox; + margin: 2px 4px; + background-color: #FFFFFF; + color: -moz-FieldText; +} + +.listcell-label { + margin: 0px !important; + padding-bottom: 1px; + padding-inline-start: 4px; + white-space: nowrap; +} + +/* ::::: listitem ::::: */ + +listitem { + border: 1px solid transparent; +} + +listitem[selected="true"] { + background-color: -moz-mac-secondaryhighlight; + color: -moz-DialogText; +} + +listbox:focus > listitem[selected="true"] { + background-color: Highlight; + color: HighlightText; +} + +/* ::::: listheader ::::: */ + +listheader { + -moz-appearance: treeheadercell; + -moz-box-align: center; + border: 2px solid; + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow; + background-color: -moz-Dialog; + color: -moz-DialogText; + padding: 0 4px; +} + +listheader[sortable="true"]:hover:active { + border-top: 2px solid; + border-right: 1px solid; + border-bottom: 1px solid; + border-left: 2px solid; + -moz-border-top-colors: ThreeDShadow -moz-Dialog; + -moz-border-right-colors: ThreeDShadow; + -moz-border-bottom-colors: ThreeDShadow; + -moz-border-left-colors: ThreeDShadow -moz-Dialog; + padding-top: 1px; + padding-inline-start: 5px; + padding-inline-end: 4px; +} + +.listheader-icon { + margin-inline-end: 2px; +} + +.listheader-label { + margin: 0px !important; +} + +/* ::::: listcell ::::: */ + +.listcell-label { + margin: 0px !important; + padding-bottom: 1px; + padding-inline-start: 4px; + white-space: nowrap; +} + +.listcell-icon { + margin-inline-end: 2px; +} + +.listcell-label[disabled="true"] { + color: GrayText; +} + +/* ::::: listcell checkbox ::::: */ + +.listcell-check { + -moz-appearance: checkbox; + -moz-box-align: center; + margin: 0px 2px; + border: 1px solid -moz-DialogText; + min-width: 13px; + min-height: 13px; + background: -moz-Field no-repeat 50% 50%; +} + +.listcell-check[checked="true"] { + background-image: url("chrome://global/skin/checkbox/cbox-check.gif"); +} + +.listcell-check[disabled="true"] { + border-color: GrayText; +} + +.listcell-check[disabled="true"][checked="true"] { + background-image: url("chrome://global/skin/checkbox/cbox-check-dis.gif"); +} diff --git a/toolkit/themes/osx/global/menu.css b/toolkit/themes/osx/global/menu.css new file mode 100644 index 0000000000..49ca168a64 --- /dev/null +++ b/toolkit/themes/osx/global/menu.css @@ -0,0 +1,187 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +menu, +menuitem, +menucaption { + -moz-appearance: menuitem; + -moz-box-align: center; + color: MenuText; + font: -moz-pull-down-menu; + list-style-image: none; + -moz-image-region: auto; + padding: 0 21px 2px; +} + +menu[disabled="true"], menuitem[disabled="true"], +menu[_moz-menuactive="true"][disabled="true"], +menuitem[_moz-menuactive="true"][disabled="true"] { + color: -moz-mac-menutextdisable; +} + +/* ..... internal content .... */ + +.menu-text, +.menu-iconic-text, +.menu-accel, +.menu-iconic-accel { + margin: 0 !important; +} + +.menu-text, +.menu-iconic-text { + font-weight: inherit; + color: inherit; +} + +menucaption > .menu-text, +menucaption > .menu-iconic-text { + font-weight: bold; +} + +.menu-description { + font-style: italic; + color: -moz-mac-menutextdisable; + margin-inline-start: 1ex !important; +} + +.menu-iconic-icon { + height: 16px; + margin-top: -2px; + margin-bottom: -2px; + margin-inline-end: 5px; + /* Empty icons shouldn't take up room, so we need to compensate + * the 5px margin-end with a negative margin-start. + */ + margin-inline-start: -5px; +} + +/* menuitems with icons */ +.menuitem-iconic, +.menu-iconic, +menuitem[image], +menuitem[src] { + /* 2px higher than those without icons */ + padding-top: 1px; + padding-bottom: 3px; +} + +.menuitem-iconic > .menu-iconic-left > .menu-iconic-icon, +.menu-iconic > .menu-iconic-left > .menu-iconic-icon, +menuitem[image] > .menu-iconic-left > .menu-iconic-icon, +menuitem[src] > .menu-iconic-left > .menu-iconic-icon { + margin-inline-start: 0; + width: 16px; +} + +/* ..... menu arrow box ..... */ + +.menu-right, +.menu-accel-container { + margin-inline-start: 21px; + margin-inline-end: -9px; + -moz-box-pack: end; +} + +.menu-right { + list-style-image: none; + -moz-appearance: menuarrow; +} + +/* ::::: menu/menuitems in menubar ::::: */ + +menubar > menu { + -moz-appearance: none; + padding: 2px 5px 2px 7px; + margin: 1px 0; +} + +menubar > menu[_moz-menuactive="true"] { + color: inherit; + background-color: transparent; +} + +menubar > menu[_moz-menuactive="true"][open="true"] { + -moz-appearance: menuitem; + color: -moz-mac-menutextselect; +} + +/* ..... internal content .... */ + +.menubar-left { + margin: 0 2px; + color: inherit; +} + +.menubar-text { + margin: 0 1px !important; + color: inherit; +} + +/* ::::: menu/menuitems in popups ::::: */ + +menupopup > menu, +menupopup > menuitem, +menupopup > menucaption { + max-width: 42em; +} + +menu[_moz-menuactive="true"], +menuitem[_moz-menuactive="true"] { + color: -moz-mac-menutextselect; + background-color: Highlight; +} + +/* ::::: menu/menuitems in menulist popups ::::: */ + +menulist > menupopup > menuitem, +menulist > menupopup > menucaption, +menulist > menupopup > menu { + max-width: none; + font: inherit; + color: -moz-FieldText; +} + +/* ::::: menuitems in editable menulist popups ::::: */ + +menulist[editable="true"] > menupopup > menuitem, +menulist[editable="true"] > menupopup > menucaption { + -moz-appearance: none; +} + +menulist[editable="true"] > menupopup > :-moz-any(menuitem, menucaption) > .menu-iconic-left { + display: none; +} + +/* ::::: checked menuitems ::::: */ + +:not(menulist) > menupopup > menuitem[checked="true"], +:not(menulist) > menupopup > menuitem[selected="true"] { + -moz-appearance: checkmenuitem; +} + +menulist:not([editable="true"]) > menupopup > menuitem[checked="true"]::before, +menulist:not([editable="true"]) > menupopup > menuitem[selected="true"]::before { + content: '\2713'; /* a checkmark */ + display: block; + width: 15px; + margin-inline-start: -15px; +} + +/* ::::: menuseparator ::::: */ + +menuseparator { + -moz-appearance: menuseparator; + margin: 5px 0; + padding: 1px 0; +} + +/* ::::: autocomplete ::::: */ + +.autocomplete-history-popup > menuitem { + max-width: none !important; + font: message-box; +} diff --git a/toolkit/themes/osx/global/menulist.css b/toolkit/themes/osx/global/menulist.css new file mode 100644 index 0000000000..a4feca947e --- /dev/null +++ b/toolkit/themes/osx/global/menulist.css @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +menulist { + -moz-appearance: menulist; + margin: 5px 2px 3px; + color: -moz-DialogText; + text-shadow: none; +} + +menulist:not([popuponly="true"]) { + min-height: 20px; +} + +.menulist-label-box { + -moz-appearance: menulist-text; + -moz-box-align: center; + -moz-box-pack: center; + margin-bottom: 1px; +} + +.menulist-label { + margin: 1px 3px !important; +} + +.menulist-description { + font-style: italic; + color: GrayText; + margin-inline-start: 1ex !important; +} + +/* ..... dropmarker ..... */ + +.menulist-dropmarker { + display: none; +} + +/* ..... disabled state ..... */ + +menulist[disabled="true"] { + color: GrayText; +} + +menulist[disabled="true"] > .menulist-dropmarker { + padding-inline-start: 7px !important; +} + +/* ::::: editable menulists ::::: */ + +menulist[editable="true"] { + -moz-appearance: menulist-textfield; + margin: 4px 2px; +} + +html|*.menulist-editable-input { + margin: 0px !important; + border: none !important; + padding: 0px !important; + background: inherit; + font: inherit; +} diff --git a/toolkit/themes/osx/global/moz.build b/toolkit/themes/osx/global/moz.build new file mode 100644 index 0000000000..635fa39c99 --- /dev/null +++ b/toolkit/themes/osx/global/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/toolkit/themes/osx/global/nativescrollbars.css b/toolkit/themes/osx/global/nativescrollbars.css new file mode 100644 index 0000000000..82ef4d2ac1 --- /dev/null +++ b/toolkit/themes/osx/global/nativescrollbars.css @@ -0,0 +1,89 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +scrollbar { + -moz-appearance: scrollbar; + -moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar); + cursor: default; + background-color: white; +} + +scrollbar[root="true"] { + position: relative; + z-index: 2147483647; /* largest positive value of a signed 32-bit integer */ +} + +html|select[size]:not([size="0"]):not([size="1"]) > scrollbar, +html|select[multiple] > scrollbar { + -moz-appearance: scrollbar-small; +} + +@media all and (-moz-overlay-scrollbars) { + scrollbar:not([active="true"]), + scrollbar[disabled="true"] { + visibility: hidden; + } +} + +/* ..... track ..... */ + +slider { + -moz-appearance: scrollbartrack-horizontal; +} + +slider[orient="vertical"] { + -moz-appearance: scrollbartrack-vertical; +} + +/* ..... thumb ..... */ + +thumb { + -moz-appearance: scrollbarthumb-horizontal; +} + +thumb[orient="vertical"] { + -moz-appearance: scrollbarthumb-vertical; +} + +/* ..... increment ..... */ + +scrollbarbutton[type="increment"] { + -moz-appearance: scrollbarbutton-right; +} + +scrollbar[orient="vertical"] > scrollbarbutton[type="increment"] { + -moz-appearance: scrollbarbutton-down; +} + +/* ..... decrement ..... */ + +scrollbarbutton[type="decrement"] { + -moz-appearance: scrollbarbutton-left; +} + +scrollbar[orient="vertical"] > scrollbarbutton[type="decrement"] { + -moz-appearance: scrollbarbutton-up; +} + +/* ::::: square at the corner of two scrollbars ::::: */ + +scrollcorner { + /* XXX -moz-appearance: scrollcorner; */ + -moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar-base); + width: 16px; + cursor: default; + background-color: white; +} + +/* ::::::::::::::::::::: MEDIA PRINT :::::::::::::::::::::: */ +@media print { + html|div scrollbar { + -moz-appearance: scrollbar; + -moz-binding: url(chrome://global/content/bindings/scrollbar.xml#scrollbar); + cursor: default; + } +} diff --git a/toolkit/themes/osx/global/netError.css b/toolkit/themes/osx/global/netError.css new file mode 100644 index 0000000000..9255f958e3 --- /dev/null +++ b/toolkit/themes/osx/global/netError.css @@ -0,0 +1,145 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This defines the look-and-feel styling of the error pages. + * (see: netError.xhtml) + * + * Original styling by William Price + * Updated by: Steven Garrity + * Henrik Skupin + */ + +html { + background: -moz-Dialog; +} + +body { + margin: 0; + padding: 0 1em; + color: -moz-FieldText; + font: message-box; +} + +h1 { + margin: 0 0 .6em 0; + border-bottom: 1px solid ThreeDLightShadow; + font-size: 160%; +} + +ul, ol { + margin: 0; + margin-inline-start: 1.5em; + padding: 0; +} + +ul > li, ol > li { + margin-bottom: .5em; +} + +ul { + list-style: square; +} + +#errorPageContainer { + position: relative; + min-width: 13em; + max-width: 52em; + margin: 4em auto; + border: 1px solid ThreeDShadow; + border-radius: 10px; + padding: 3em; + padding-inline-start: 30px; + background: url("chrome://global/skin/icons/warning-large.png") left 0 no-repeat -moz-Field; + background-origin: content-box; +} + +#errorPageContainer.certerror { + background-image: url("chrome://global/skin/icons/sslWarning.png"); +} + +#errorPageContainer:dir(rtl) { + background-position: right 0; +} + +#errorTitle { + margin-inline-start: 80px; +} + +#errorLongContent { + margin-inline-start: 80px; +} + +#errorShortDesc > p { + overflow: auto; + border-bottom: 1px solid ThreeDLightShadow; + padding-bottom: 1em; + font-size: 130%; + white-space: pre-wrap; +} + +#errorLongDesc { + padding-inline-end: 3em; + font-size: 110%; +} + +#errorLongDesc > p { +} + +#errorTryAgain { + margin-top: 2em; + margin-inline-start: 80px; +} + +#brand { + position: absolute; + right: 0; + bottom: -1.5em; + margin-inline-end: 10px; + opacity: .4; +} + +#brand:dir(rtl) { + right: auto; + left: 0; +} + +#brand > p { + margin: 0; +} + +#errorContainer { + display: none; +} + +#securityOverrideDiv { + padding-top: 10px; +} + +#securityOverrideContent { + background-color: #FFF090; /* Pale yellow */ + padding: 10px; + border-radius: 10px; +} + +/* Custom styling for 'blacklist' error class */ +:root.blacklist #errorTitle, :root.blacklist #errorLongContent, +:root.blacklist #errorShortDesc, :root.blacklist #errorLongDesc, +:root.blacklist a { + background-color: #722; /* Dark red */ + color: white; +} + +:root.blacklist #errorPageContainer { + background-image: url("chrome://global/skin/icons/blacklist_64.png"); + background-color: #722; +} + +:root.blacklist { + background: #333; +} + +:root.blacklist #errorTryAgain { + display: none; +} diff --git a/toolkit/themes/osx/global/notification.css b/toolkit/themes/osx/global/notification.css new file mode 100644 index 0000000000..6d22cf9c86 --- /dev/null +++ b/toolkit/themes/osx/global/notification.css @@ -0,0 +1,206 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include shared.inc +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +notification { + padding: 3px 3px 4px; + text-shadow: none; +} + +notification[type="info"] { + color: rgba(255,255,255,0.95); + background: linear-gradient(#606060, #404040); + border-top: 1px solid #2a2a2a; + border-bottom: 1px solid #2a2a2a; +} + +notification[type="warning"] { + color: rgba(0,0,0,0.95); + background: linear-gradient(#ffe13e, #ffc703); + border-top: 1px solid #bf8a01; + border-bottom: 1px solid #bf8a01; +} + +notification[type="critical"] { + color: rgba(255,255,255,0.95); + background: linear-gradient(#d40000, #980000); + border-top: 1px solid #5d0000; + border-bottom: 1px solid #5d0000; +} + +notificationbox[notificationside="top"] > notification { + border-top-style: none; +} + +notificationbox[notificationside="bottom"] > notification { + border-bottom-style: none; +} + +.messageText > .text-link { + color: inherit !important; + text-decoration: underline; +} + +.messageImage { + width: 16px; + height: 16px; + margin: 0 4px; +} + +/* Default icons for notifications */ + +.messageImage[type="info"] { + list-style-image: url("chrome://global/skin/notification/info-icon.png"); +} + +.messageImage[type="warning"] { + list-style-image: url("chrome://global/skin/notification/warning-icon.png"); +} + +.messageImage[type="critical"] { + list-style-image: url("chrome://global/skin/notification/error-icon.png"); +} + +.messageText { + margin: 0 3px !important; + padding: 0; + font-weight: bold; +} + +.messageCloseButton { + -moz-appearance: none; + padding: 0; + margin: 0 2px; + border: none; +} + +/* + Invert the close icon for @type=info since both are normally dark. It's unclear + why !important is necessary here so remove it if it's no longer needed. +*/ +notification[type="info"] .close-icon:not(:hover) { + -moz-image-region: rect(0, 64px, 16px, 48px) !important; +} + +@media (min-resolution: 2dppx) { + notification[type="info"] .close-icon:not(:hover) { + -moz-image-region: rect(0, 128px, 32px, 96px) !important; + } +} + +.messageCloseButton:-moz-focusring > .toolbarbutton-icon { + border-radius: 10000px; + box-shadow: 0 0 2px 1px -moz-mac-focusring, + 0 0 0 2px -moz-mac-focusring inset; +} + +@media (min-resolution: 2dppx) { + .messageCloseButton > .toolbarbutton-icon { + width: 16px; + } +} + +/* Popup notification */ + +.popup-notification-body { + max-width: 25em; +} + +.popup-notification-origin:not([value]), +.popup-notification-learnmore-link:not([href]) { + display: none; +} + +.popup-notification-origin { + margin-bottom: .3em !important; +} + +.popup-notification-learnmore-link { + margin-top: .5em !important; +} + +.popup-notification-button-container { + margin-top: 17px; +} + +.popup-notification-menubutton { + -moz-appearance: none; +} + +.popup-notification-menubutton:not([type="menu-button"]):-moz-focusring, +.popup-notification-menubutton:-moz-focusring > .button-menubutton-dropmarker, +.popup-notification-menubutton > .button-menubutton-button:-moz-focusring { + box-shadow: @focusRingShadow@; + position: relative; +} + +.popup-notification-menubutton:not([type="menu-button"]), +.popup-notification-menubutton > .button-menubutton-button, +.popup-notification-menubutton > .button-menubutton-dropmarker { + -moz-appearance: none; + color: #434343; + border-radius: 4px; + border: 1px solid #b5b5b5; + background: linear-gradient(#fff, #f2f2f2); + box-shadow: inset 0 1px rgba(255,255,255,.8), + inset 0 0 1px rgba(255,255,255,.25), + 0 1px rgba(255,255,255,.3); + background-clip: padding-box; + background-origin: padding-box; + padding: 2px 6px; +} + +.popup-notification-menubutton > .button-menubutton-button { + -moz-appearance: none; + margin: 0; + padding-top: 2px; + padding-bottom: 2px; + padding-inline-start: 8px; + padding-inline-end: 5px; +} + +.popup-notification-menubutton > .button-menubutton-dropmarker { + padding: 7px 8px; + margin-top: 0; + margin-bottom: 0; + margin-inline-start: -1px; + list-style-image: url("chrome://global/skin/icons/panel-dropmarker.png"); +} + +.popup-notification-menubutton > .button-menubutton-button:-moz-locale-dir(ltr), +.popup-notification-menubutton > .button-menubutton-dropmarker:-moz-locale-dir(rtl) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.popup-notification-menubutton > .button-menubutton-button:-moz-locale-dir(rtl), +.popup-notification-menubutton > .button-menubutton-dropmarker:-moz-locale-dir(ltr) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.popup-notification-menubutton:not([type="menu-button"]):hover:active, +.popup-notification-menubutton > .button-menubutton-button:hover:active, +.popup-notification-menubutton[open="true"] > .button-menubutton-dropmarker { + box-shadow: inset 0 1px 4px -3px #000, 0 1px rgba(255, 255, 255, 0.3); +} + +.popup-notification-closebutton { + margin-inline-end: -12px; + margin-top: -13px; +} + +.popup-notification-closeitem > .menu-iconic-left { + display: none; +} + +.popup-notification-menubutton > .button-menubutton-button[disabled] { + opacity: 0.5; +} + +.popup-notification-warning { + color: #aa1b08; +} diff --git a/toolkit/themes/osx/global/notification/close.png b/toolkit/themes/osx/global/notification/close.png new file mode 100644 index 0000000000..3300a4d61e Binary files /dev/null and b/toolkit/themes/osx/global/notification/close.png differ diff --git a/toolkit/themes/osx/global/notification/error-icon.png b/toolkit/themes/osx/global/notification/error-icon.png new file mode 100644 index 0000000000..54cc7e663b Binary files /dev/null and b/toolkit/themes/osx/global/notification/error-icon.png differ diff --git a/toolkit/themes/osx/global/notification/info-icon.png b/toolkit/themes/osx/global/notification/info-icon.png new file mode 100644 index 0000000000..55d45f165c Binary files /dev/null and b/toolkit/themes/osx/global/notification/info-icon.png differ diff --git a/toolkit/themes/osx/global/notification/warning-icon.png b/toolkit/themes/osx/global/notification/warning-icon.png new file mode 100644 index 0000000000..13cf79d6df Binary files /dev/null and b/toolkit/themes/osx/global/notification/warning-icon.png differ diff --git a/toolkit/themes/osx/global/numberbox.css b/toolkit/themes/osx/global/numberbox.css new file mode 100644 index 0000000000..e5de22d218 --- /dev/null +++ b/toolkit/themes/osx/global/numberbox.css @@ -0,0 +1,33 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +textbox[type="number"] { + -moz-appearance: none; + -moz-box-align: center; + padding: 0 !important; + border: none; + background-color: transparent; + cursor: default; +} + +html|*.numberbox-input { + text-align: right; + padding: 0 1px !important; +} + +.numberbox-input-box { + -moz-appearance: textfield; + margin-right: 4px; + border: 3px solid; + -moz-border-top-colors: transparent #888888 #000000; + -moz-border-right-colors: transparent #FFFFFF #000000; + -moz-border-bottom-colors: transparent #FFFFFF #000000; + -moz-border-left-colors: transparent #888888 #000000; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + background-color: -moz-Field; +} diff --git a/toolkit/themes/osx/global/popup.css b/toolkit/themes/osx/global/popup.css new file mode 100644 index 0000000000..cf0266a3a6 --- /dev/null +++ b/toolkit/themes/osx/global/popup.css @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +menupopup, +panel { + -moz-appearance: menupopup; + background-color: Menu; +} + +menupopup > menu > menupopup { + margin-top: -4px; +} + +.popup-internal-box { + padding: 4px 0; +} + +panel[titlebar] { + -moz-appearance: none; /* to disable rounded corners */ +} + +panel[type="arrow"] { + -moz-appearance: none; + background: transparent; +} + +panel[type="arrow"][side="top"], +panel[type="arrow"][side="bottom"] { + margin-left: -25px; + margin-right: -25px; +} + +panel[type="arrow"][side="left"], +panel[type="arrow"][side="right"] { + margin-top: -25px; + margin-bottom: -25px; +} + +.panel-arrowcontent { + -moz-appearance: none; + background: var(--arrowpanel-background); + border-radius: var(--arrowpanel-border-radius); + box-shadow: 0 0 0 1px var(--arrowpanel-border-color); + color: var(--arrowpanel-color); + border: none; + padding: var(--arrowpanel-padding); + margin: 1px; +} + +.panel-arrow[side="top"] { + list-style-image: var(--panel-arrow-image-vertical, + url("chrome://global/skin/arrow/panelarrow-vertical.png")); + margin-left: 16px; + margin-right: 16px; + margin-bottom: -1px; +} + +.panel-arrow[side="bottom"] { + list-style-image: url("chrome://global/skin/arrow/panelarrow-vertical.png"); + -moz-transform: scaleY(-1); + margin-left: 16px; + margin-right: 16px; + margin-top: -1px; +} + +.panel-arrow[side="left"] { + list-style-image: url("chrome://global/skin/arrow/panelarrow-horizontal.png"); + margin-top: 16px; + margin-bottom: 16px; + margin-right: -1px; +} + +.panel-arrow[side="right"] { + list-style-image: url("chrome://global/skin/arrow/panelarrow-horizontal.png"); + transform: scaleX(-1); + margin-top: 16px; + margin-bottom: 16px; + margin-left: -1px; +} + +@media (min-resolution: 2dppx) { + .panel-arrow[side="top"], + .panel-arrow[side="bottom"] { + list-style-image: var(--panel-arrow-image-vertical, + url("chrome://global/skin/arrow/panelarrow-vertical@2x.png")); + width: 18px; + height: 10px; + } + + .panel-arrow[side="left"], + .panel-arrow[side="right"] { + list-style-image: url("chrome://global/skin/arrow/panelarrow-horizontal@2x.png"); + width: 10px; + height: 18px; + } +} + +/* ::::: tooltip ::::: */ + +tooltip { + -moz-appearance: tooltip; + margin-top: 18px; + padding: 2px 3px; + max-width: 40em; + color: InfoText; + font: message-box; + cursor: default; +} + +tooltip[titletip="true"] { + /* See bug 32157 comment 128 + * margin: -2px 0px 0px -3px; + */ + max-width: none; +} + +/* rules for popups associated with menulists */ + +menulist > menupopup { + min-width: 0px; +} + +menulist > menupopup:not([position]) { + margin-inline-start: -13px; + margin-top: -2px; +} + +menulist[editable="true"] > menupopup { + -moz-appearance: none; +} + +menulist > menupopup > .popup-internal-box { + padding: 0; +} + +menulist:not([editable="true"]) > menupopup { + padding: 4px 0; +} diff --git a/toolkit/themes/osx/global/preferences.css b/toolkit/themes/osx/global/preferences.css new file mode 100644 index 0000000000..d0b82a819c --- /dev/null +++ b/toolkit/themes/osx/global/preferences.css @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +prefwindow { + padding: 0; + font: -moz-dialog !important; +} + +prefpane { + padding: 12px 12px 0 12px; +} + +prefwindow[type="child"] > prefpane { + padding: 0; +} + +.prefWindow-dlgbuttons { + margin: 0 12px 12px; + padding-top: 0 !important; +} + +.paneSelector { + font: message-box; + padding: 1px 4px; + -moz-appearance: toolbar; + margin: 0; +} + +radio[pane] { + border: solid transparent; + border-width: 0 2px; + padding: 5px 4px 3px; + margin: 0; + -moz-appearance: none; + text-shadow: rgba(255, 255, 255, 0.4) 0 1px; +} + +radio[pane]:active:hover { + text-shadow: none; +} + +radio[pane] > .paneButtonIcon { + /* preload external filter file */ + background-image: url("chrome://global/skin/filters.svg"); +} + +radio[pane]:active:hover > .paneButtonIcon { + filter: url("chrome://global/skin/filters.svg#iconPressed"); +} + +radio[pane][selected="true"] { + -moz-border-image: url("chrome://global/skin/icons/panebutton-active.png") 0 2 fill repeat stretch; +} + +radio[pane][selected="true"]:-moz-window-inactive { + -moz-border-image: url("chrome://global/skin/icons/panebutton-inactive.png") 0 2 fill repeat stretch; +} + +.paneButtonLabel { + margin: 0 !important; +} diff --git a/toolkit/themes/osx/global/progressmeter.css b/toolkit/themes/osx/global/progressmeter.css new file mode 100644 index 0000000000..13fce252ab --- /dev/null +++ b/toolkit/themes/osx/global/progressmeter.css @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +progressmeter { + -moz-appearance: progressbar; + margin: 2px 4px; + min-width: 128px; + height: 12px; +} + +.progress-remainder[flex="100"], .progress-remainder[flex="0"] { + background-image: none !important; + -moz-appearance: none; +} + +.progressmeter-statusbar { + margin: 0; + border-width: 1px; +} diff --git a/toolkit/themes/osx/global/radio.css b/toolkit/themes/osx/global/radio.css new file mode 100644 index 0000000000..e21d93011b --- /dev/null +++ b/toolkit/themes/osx/global/radio.css @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +radiogroup { + margin: 1px 0px 1px 0px; +} + +radio { + -moz-appearance: radio-container; + -moz-box-align: center; + margin: 4px 2px; + -moz-user-focus: ignore; +} + +.radio-label-box { + margin-inline-start: 0px; + padding: 0px; +} + +.radio-icon { + margin-inline-end: 2px; +} + +.radio-label { + margin: 1px 0 !important; +} + +radio[disabled="true"] { + color: GrayText !important; +} + +.radio-check, .radio-check-box1 { + -moz-appearance: radio; + margin: 0 1px 1px; + /* vertical-align tells native theming where to snap to. However, this doesn't + * always work reliably because of bug 503833. */ + vertical-align: bottom; + width: 1.3em; + height: 1.3em; +} diff --git a/toolkit/themes/osx/global/resizer.css b/toolkit/themes/osx/global/resizer.css new file mode 100644 index 0000000000..18cdd2bc93 --- /dev/null +++ b/toolkit/themes/osx/global/resizer.css @@ -0,0 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +resizer { + -moz-appearance: resizer; + background: url("chrome://global/skin/icons/resizer.png") no-repeat; + background-size: 100% 100%; + cursor: se-resize; + min-width: 15px; + width: 15px; + min-height: 15px; + height: 15px; +} +@media (min-resolution: 2dppx) { + resizer { + background-image: url("chrome://global/skin/icons/resizer@2x.png"); + background-size: 100% 100%; + } +} + +resizer[type="window"] { + display: none; +} + +resizer[rtl="true"], +resizer[dir="bottomend"]:-moz-locale-dir(rtl) { + background: url("chrome://global/skin/icons/resizer-rtl.png") no-repeat; +} +@media (min-resolution: 2dppx) { + resizer[rtl="true"], + resizer[dir="bottomend"]:-moz-locale-dir(rtl) { + background-image: url("chrome://global/skin/icons/resizer-rtl@2x.png"); + background-size: 100% 100%; + } +} + + +resizer[dir="left"], +resizer[dir="bottomleft"], +resizer[dir="bottomstart"] { + transform: scaleX(-1); +} + +resizer[dir="bottomleft"], +resizer[dir="bottomstart"]:not([rtl="true"]):not(:-moz-locale-dir(rtl)), +resizer[dir="bottomend"][rtl="true"] { + cursor: sw-resize; +} + +resizer[dir="top"], +resizer[dir="bottom"] { + cursor: ns-resize; +} + +resizer[dir="left"], +resizer[dir="right"] { + cursor: ew-resize; +} + +resizer[dir="topleft"] { + cursor: nw-resize; +} + +resizer[dir="topright"] { + cursor: ne-resize; +} diff --git a/toolkit/themes/osx/global/richlistbox.css b/toolkit/themes/osx/global/richlistbox.css new file mode 100644 index 0000000000..605c89abb3 --- /dev/null +++ b/toolkit/themes/osx/global/richlistbox.css @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +richlistbox { + -moz-appearance: listbox; + margin: 2px 4px; + background-color: -moz-Field; + color: -moz-FieldText; +} + +richlistbox[disabled="true"] { + color: GrayText; +} + +richlistitem[selected="true"] { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +richlistbox:focus > richlistitem[selected="true"] { + background-color: Highlight; + color: HighlightText; +} + diff --git a/toolkit/themes/osx/global/scale.css b/toolkit/themes/osx/global/scale.css new file mode 100644 index 0000000000..2e090bf28d --- /dev/null +++ b/toolkit/themes/osx/global/scale.css @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +.scale-slider { + -moz-appearance: scale-horizontal; + background: url("chrome://global/skin/scale/scale-tray-horiz.gif") 0% 50% repeat-x; + margin: 2px 4px; + width: 100px; +} + +.scale-slider[orient="vertical"] +{ + -moz-appearance: scale-vertical; + background: url("chrome://global/skin/scale/scale-tray-vert.gif") 50% 0% repeat-y; + margin: 4px 2px; + width: auto; + height: 100px; +} + +.scale-thumb { + -moz-appearance: scalethumb-horizontal; + border: 2px solid; + -moz-border-top-colors: ThreeDLightShadow ThreeDHighlight; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDLightShadow ThreeDHighlight; + background-color: -moz-Dialog; + min-width: 30px; + min-height: 15px; +} + +.scale-thumb[orient="vertical"] { + -moz-appearance: scalethumb-vertical; + min-width: 15px; + min-height: 30px; +} + +.scale-thumb[disabled="true"] { + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow !important; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow !important; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow !important; + -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow !important; +} diff --git a/toolkit/themes/osx/global/scale/scale-tray-horiz.gif b/toolkit/themes/osx/global/scale/scale-tray-horiz.gif new file mode 100644 index 0000000000..b87fe68c15 Binary files /dev/null and b/toolkit/themes/osx/global/scale/scale-tray-horiz.gif differ diff --git a/toolkit/themes/osx/global/scale/scale-tray-vert.gif b/toolkit/themes/osx/global/scale/scale-tray-vert.gif new file mode 100644 index 0000000000..97687b2e22 Binary files /dev/null and b/toolkit/themes/osx/global/scale/scale-tray-vert.gif differ diff --git a/toolkit/themes/osx/global/scrollbox.css b/toolkit/themes/osx/global/scrollbox.css new file mode 100644 index 0000000000..c9b7276698 --- /dev/null +++ b/toolkit/themes/osx/global/scrollbox.css @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* Horizontal enabled */ +.autorepeatbutton-up[orient="horizontal"], +.scrollbutton-up[orient="horizontal"] { + list-style-image: url("chrome://global/skin/arrow/arrow-lft-sharp.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +.autorepeatbutton-down[orient="horizontal"], +.scrollbutton-down[orient="horizontal"] { + list-style-image: url("chrome://global/skin/arrow/arrow-rit-sharp.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +/* Horizontal disabled */ +.autorepeatbutton-up[orient="horizontal"][disabled="true"], +.scrollbutton-up[orient="horizontal"][disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +.autorepeatbutton-down[orient="horizontal"][disabled="true"], +.scrollbutton-down[orient="horizontal"][disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +/* Vertical enabled */ +.autorepeatbutton-up:not([orient="horizontal"]), +.scrollbutton-up { + list-style-image: url("chrome://global/skin/arrow/arrow-up-sharp.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +.autorepeatbutton-down:not([orient="horizontal"]), +.scrollbutton-down { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-sharp.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +/* Vertical disabled */ +.autorepeatbutton-up[disabled="true"]:not([orient="horizontal"]), +.scrollbutton-up[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +.autorepeatbutton-down[disabled="true"]:not([orient="horizontal"]), +.scrollbutton-down[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); + -moz-image-region: auto; /* cut off inheritance */ +} + +.scrollbutton-up > .toolbarbutton-text, +.scrollbutton-down > .toolbarbutton-text { + display: none; +} diff --git a/toolkit/themes/osx/global/shared.inc b/toolkit/themes/osx/global/shared.inc new file mode 100644 index 0000000000..350fed1721 --- /dev/null +++ b/toolkit/themes/osx/global/shared.inc @@ -0,0 +1,20 @@ +%filter substitution + +%define loweredShadow 0 1px rgba(255, 255, 255, .4) +%define focusRingShadow 0 0 1px -moz-mac-focusring inset, 0 0 4px 1px -moz-mac-focusring, 0 0 1.5px 1px -moz-mac-focusring +%define yosemiteFocusRingShadow 0 0 0 0.5px -moz-mac-focusring inset, 0 0 0 2px -moz-mac-focusring + +%define roundButtonBorder 1px solid rgba(0,0,0,.35) +%define roundButtonBackground linear-gradient(#f6f6f6, #e9e9e9) +%define roundButtonShadow 0 1px rgba(255,255,255,.5), inset 0 1px 1px rgba(255,255,255,.5) +%define roundButtonPressedBackground #dadada +%define roundButtonPressedShadow 0 1px rgba(255,255,255,.4), inset 0 1px 3px rgba(0,0,0,.2) + +%define scopeBarBackground linear-gradient(#E8E8E8, #D0D0D0) repeat-x +%define scopeBarSeparatorBorder 1px solid #888 +%define scopeBarTitleColor #6D6D6D + +%define toolbarbuttonCornerRadius 3px +%define toolbarbuttonBackground linear-gradient(#FFF, #ADADAD) repeat-x +%define toolbarbuttonPressedInnerShadow inset rgba(0, 0, 0, 0.3) 0 -6px 10px, inset #000 0 1px 3px, inset rgba(0, 0, 0, 0.2) 0 1px 3px +%define toolbarbuttonInactiveBorderColor rgba(146, 146, 146, 0.84) diff --git a/toolkit/themes/osx/global/spinbuttons.css b/toolkit/themes/osx/global/spinbuttons.css new file mode 100644 index 0000000000..bf89520f68 --- /dev/null +++ b/toolkit/themes/osx/global/spinbuttons.css @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +spinbuttons { + height: 24px; + min-height: 24px; + -moz-appearance: spinner; + cursor: default; +} + +.spinbuttons-up { + -moz-appearance: none; + -moz-box-flex: 1; + min-width: 1px; + min-height: 1px; + margin: 0; + padding: 0; +} + +.spinbuttons-down { + -moz-appearance: none; + -moz-box-flex: 1; + min-width: 1px; + min-height: 1px; + margin: 0; + padding: 0; +} + diff --git a/toolkit/themes/osx/global/splitter.css b/toolkit/themes/osx/global/splitter.css new file mode 100644 index 0000000000..caaa83ad0a --- /dev/null +++ b/toolkit/themes/osx/global/splitter.css @@ -0,0 +1,124 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +/* ::::: splitter (vertical) ::::: */ + +splitter { + -moz-box-align: center; + -moz-box-pack: center; + cursor: ew-resize; + min-width: 9px; + min-height: 9px; + background: url("chrome://global/skin/splitter/dimple.png") transparent no-repeat center; +} + +splitter[state="collapsed"][collapse="before"], +splitter[state="collapsed"][substate="before"], +splitter[state="collapsed"][collapse="after"]:-moz-locale-dir(rtl), +splitter[state="collapsed"][substate="after"]:-moz-locale-dir(rtl) { + cursor: e-resize; +} + +splitter[state="collapsed"][collapse="after"], +splitter[state="collapsed"][substate="after"], +splitter[state="collapsed"][collapse="before"]:-moz-locale-dir(rtl), +splitter[state="collapsed"][substate="before"]:-moz-locale-dir(rtl) { + cursor: w-resize; +} + +splitter:-moz-lwtheme { + background: none; +} + +/* ::::: splitter (horizontal) ::::: */ + +splitter[orient="vertical"] { + cursor: ns-resize; + min-width: 0px; + min-height: 9px; + min-width: 9px; + background: url("chrome://global/skin/splitter/dimple.png") transparent no-repeat center; +} + +splitter[orient="vertical"][state="collapsed"][collapse="before"], +splitter[orient="vertical"][state="collapsed"][substate="before"] { + cursor: s-resize; +} + +splitter[orient="vertical"][state="collapsed"][collapse="after"], +splitter[orient="vertical"][state="collapsed"][substate="after"] { + cursor: n-resize; +} + +splitter[disabled="true"] { + cursor: default !important; +} + +/* ::::: splitter grippy ::::: */ + +grippy { + cursor: pointer; + margin: 0px 1px; + min-width: 4px; + min-height: 115px; + background-color: transparent; + background-repeat: no-repeat; +} + +grippy:hover { + background-color: ThreeDHighlight; +} + +splitter[orient="vertical"] > grippy { + margin: 1px 0px; + min-width: 115px; + min-height: 4px; +} + +/* ..... normal state ..... */ + +/* vertical grippies */ +splitter[collapse="before"] > grippy, +splitter[collapse="after"] > grippy:-moz-locale-dir(rtl) { + background-image: url("chrome://global/skin/splitter/grip-left.gif"); +} + +splitter[collapse="after"] > grippy, +splitter[collapse="before"] > grippy:-moz-locale-dir(rtl) { + background-image: url("chrome://global/skin/splitter/grip-right.gif"); +} + +/* horizontal grippies */ +splitter[collapse="before"][orient="vertical"] > grippy { + background-image: url("chrome://global/skin/splitter/grip-top.gif"); +} + +splitter[collapse="after"][orient="vertical"] > grippy { + background-image: url("chrome://global/skin/splitter/grip-bottom.gif"); +} + +/* ..... collapsed state ..... */ + +/* vertical grippies */ +splitter[collapse="before"][state="collapsed"] > grippy, +splitter[collapse="after"][state="collapsed"] > grippy:-moz-locale-dir(rtl) { + background-image: url("chrome://global/skin/splitter/grip-right.gif"); +} + +splitter[collapse="after"][state="collapsed"] > grippy, +splitter[collapse="before"][state="collapsed"] > grippy:-moz-locale-dir(rtl) { + background-image: url("chrome://global/skin/splitter/grip-left.gif"); +} + +/* horizontal grippies */ +splitter[collapse="before"][state="collapsed"][orient="vertical"] > grippy { + background-image: url("chrome://global/skin/splitter/grip-bottom.gif"); +} + +splitter[collapse="after"][state="collapsed"][orient="vertical"] > grippy { + background-image: url("chrome://global/skin/splitter/grip-top.gif"); +} + diff --git a/toolkit/themes/osx/global/splitter/dimple.png b/toolkit/themes/osx/global/splitter/dimple.png new file mode 100644 index 0000000000..4d0b91bfea Binary files /dev/null and b/toolkit/themes/osx/global/splitter/dimple.png differ diff --git a/toolkit/themes/osx/global/splitter/grip-bottom.gif b/toolkit/themes/osx/global/splitter/grip-bottom.gif new file mode 100644 index 0000000000..af6290fe9d Binary files /dev/null and b/toolkit/themes/osx/global/splitter/grip-bottom.gif differ diff --git a/toolkit/themes/osx/global/splitter/grip-left.gif b/toolkit/themes/osx/global/splitter/grip-left.gif new file mode 100644 index 0000000000..6be9bc4f40 Binary files /dev/null and b/toolkit/themes/osx/global/splitter/grip-left.gif differ diff --git a/toolkit/themes/osx/global/splitter/grip-right.gif b/toolkit/themes/osx/global/splitter/grip-right.gif new file mode 100644 index 0000000000..71be69083e Binary files /dev/null and b/toolkit/themes/osx/global/splitter/grip-right.gif differ diff --git a/toolkit/themes/osx/global/splitter/grip-top.gif b/toolkit/themes/osx/global/splitter/grip-top.gif new file mode 100644 index 0000000000..3cba005946 Binary files /dev/null and b/toolkit/themes/osx/global/splitter/grip-top.gif differ diff --git a/toolkit/themes/osx/global/tabbox.css b/toolkit/themes/osx/global/tabbox.css new file mode 100644 index 0000000000..4fcbac486d --- /dev/null +++ b/toolkit/themes/osx/global/tabbox.css @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + The default style of these tabs is that of an NSTabView with tabs at + the top in the "regular" size. These tabs can be used with or without + a tabbox element. + For bottom tabs you should use the "tabs-bottom" class on the tabbox + or the tabs element. Bottom tabs use a style that's similar to the + one used in Adium. +*/ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +tabbox { + margin: 0 5px; +} + +tabpanels { + -moz-appearance: tabpanels; + padding: 33px 15px 15px; +} + +tabs { + -moz-box-align: center; + font: menu; +} + +tabbox > tabs { + padding: 0 10px; + margin-bottom: -12px; + position: relative; +} + +tab { + -moz-appearance: tab; +} + +tab:-moz-focusring { + /* Tab focus rings need to overlay adjacent tabs. */ + position: relative; +} + +tab:first-of-type { + padding-inline-start: 2px; +} + +tab:last-of-type { + padding-inline-end: 2px; +} + +tab[visuallyselected="true"] { + color: #FFF; + text-shadow: rgba(0, 0, 0, 0.4) 0 1px; +} + +.tab-middle { + padding: 1px 6px 2px; +} + +.tabs-left, +.tabs-right { + -moz-box-flex: 1; +} + +/* Tabs at the bottom + * These tabs are smaller, left aligned and don't extend into the tabpanel. + */ + +tabbox.tabs-bottom > tabpanels { + padding: 10px; +} + +tabbox.tabs-bottom > tabs, +tabs.tabs-bottom { + background-color: rgba(0, 0, 0, 0.1); + padding: 0; + margin: 0; + border-top: 2px solid; + -moz-border-top-colors: #888 rgba(0, 0, 0, 0.08); + -moz-box-align: start; + font: message-box; +} + +tabbox.tabs-bottom > tabs > .tabs-left, +tabs.tabs-bottom > .tabs-left { + -moz-box-flex: 0; +} + +tabbox.tabs-bottom > tabs > tab, +tabs.tabs-bottom > tab { + -moz-appearance: none; + margin: -1px 0 0; + padding: 0 0 2px 0; + position: relative; + border-inline-end: 1px solid rgba(0, 0, 0, 0.19); +} + +tabbox.tabs-bottom > tabs > tab > .tab-middle, +tabs.tabs-bottom > tab > .tab-middle { + padding: 1px 2px 0 2px; +} + +tabbox.tabs-bottom > tabs > tab:not([visuallyselected=true]):hover, +tabs.tabs-bottom > tab:not([visuallyselected=true]):hover { + background-color: rgba(0, 0, 0, 0.1); + border-inline-end-color: rgba(0, 0, 0, 0.1); +} + +tabbox.tabs-bottom > tabs > tab[visuallyselected=true], +tabs.tabs-bottom > tab[visuallyselected=true] { + color: #000; + text-shadow: none; + border: solid #888; + border-width: 0 2px 2px; + border-radius: 2px; + -moz-border-left-colors: rgba(0, 0, 0, 0.08) #888; + -moz-border-right-colors: rgba(0, 0, 0, 0.08) #888; + -moz-border-bottom-colors: rgba(0, 0, 0, 0.08) #888; + margin-inline-end: -1px; + margin-top: -2px; + margin-bottom: 1px; + padding: 0; +} + +tabbox.tabs-bottom > tabs > tab[beforeselected=true], +tabs.tabs-bottom > tab[beforeselected=true] { + border-inline-end-color: transparent; + margin-inline-end: -2px; +} + +tabbox.tabs-bottom > tabs > tab:first-of-type:not([visuallyselected=true]), +tabs.tabs-bottom > tab:first-of-type:not([visuallyselected=true]) { + border-inline-start: 4px solid transparent; +} + +tabbox.tabs-bottom > tabs > tab:first-of-type[visuallyselected=true], +tabs.tabs-bottom > tab:first-of-type[visuallyselected=true] { + margin-inline-start: 2px; +} + +tabbox.tabs-bottom, +tabbox.tabs-bottom > tabpanels, +tabbox.tabs-bottom > tabs > tab[visuallyselected=true] > .tab-middle, +tabs.tabs-bottom > tab[visuallyselected=true] > .tab-middle { + -moz-appearance: dialog; +} diff --git a/toolkit/themes/osx/global/tabprompts.css b/toolkit/themes/osx/global/tabprompts.css new file mode 100644 index 0000000000..14a23f2696 --- /dev/null +++ b/toolkit/themes/osx/global/tabprompts.css @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Tab Modal Prompt boxes */ +tabmodalprompt { + background-image: url(chrome://global/skin/icons/tabprompts-bgtexture.png); + background-color: hsla(0,0%,10%,.5); + font-family: sans-serif; /* use content font not system UI font */ + font-size: 110%; +} + +.mainContainer { + color: black; + background-color: hsla(0,0%,100%,.95); + background-clip: padding-box; + border-radius: 2px; + border: 1px solid hsla(0,0%,0%,.5); +} + +.topContainer { + padding: 20px; +} + +.buttonContainer { + padding: 12px 20px 15px; + background-color: hsla(0,0%,0%,.05); + border-top: 1px solid hsla(0,0%,0%,.05); +} + +button { + -moz-appearance: none; + padding: 2px 0; + margin: 0; + margin-inline-start: 8px; + border-radius: 2px; + color: black !important; + background-color: hsl(0,0%,90%); + background-image: linear-gradient(hsla(0,0%,100%,.7), transparent); + background-clip: padding-box; + border: 1px solid; + border-color: hsl(0,0%,65%) hsl(0,0%,60%) hsl(0,0%,50%); + box-shadow: 0 1px 0 hsla(0,0%,100%,.9) inset, + 0 1px 2px hsla(0,0%,0%,.1); +} + + +button[default=true] { + background-color: hsl(0,0%,79%); +} + +button:hover { + background-color: hsl(0,0%,96%); +} + +button:hover:active { + background-image: linear-gradient(hsla(0,0%,100%,.2), transparent); + background-color: hsl(0,0%,70%); + box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset, + 0 1px 3px hsla(0,0%,0%,.2); +} + +button:focus { + box-shadow: 0 0 1px -moz-mac-focusring inset, + 0 0 4px 1px -moz-mac-focusring, + 0 0 1.5px 1px -moz-mac-focusring; +} diff --git a/toolkit/themes/osx/global/textbox.css b/toolkit/themes/osx/global/textbox.css new file mode 100644 index 0000000000..d7a31c7acc --- /dev/null +++ b/toolkit/themes/osx/global/textbox.css @@ -0,0 +1,102 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); +@namespace html url("http://www.w3.org/1999/xhtml"); + +textbox { + -moz-appearance: textfield; + cursor: text; + margin: 4px; + border: 3px solid; + -moz-border-top-colors: transparent #888888 #000000; + -moz-border-right-colors: transparent #FFFFFF #000000; + -moz-border-bottom-colors: transparent #FFFFFF #000000; + -moz-border-left-colors: transparent #888888 #000000; + border-top-right-radius: 2px; + border-bottom-left-radius: 2px; + padding: 0px; + background-color: -moz-Field; + color: -moz-FieldText; +} + +html|*.textbox-input, +html|*.textbox-textarea { + margin: 0px !important; + border: none !important; + padding: 0px 1px !important; + background-color: inherit; + color: inherit; + font: inherit; +} + +.textbox-contextmenu { + cursor: default; +} + +textbox[focused="true"] { + -moz-border-top-colors: -moz-mac-focusring -moz-mac-focusring #000000; + -moz-border-right-colors: -moz-mac-focusring -moz-mac-focusring #000000; + -moz-border-bottom-colors: -moz-mac-focusring -moz-mac-focusring #000000; + -moz-border-left-colors: -moz-mac-focusring -moz-mac-focusring #000000; +} + +textbox[readonly="true"] { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +textbox[disabled="true"] { + cursor: default; + -moz-border-top-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-right-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-bottom-colors: transparent ThreeDShadow -moz-Dialog; + -moz-border-left-colors: transparent ThreeDShadow -moz-Dialog; + background-color: -moz-Dialog; + color: GrayText; +} + +textbox.plain { + -moz-appearance: none !important; + background-color: transparent; + padding: 0px !important; + margin: 0px !important; + border: none !important; +} + +textbox.plain html|*.textbox-input, +textbox.plain html|*.textbox-textarea { + padding: 0px !important; +} + +/* ::::: search box ::::: */ + +textbox[type="search"] { + -moz-appearance: searchfield; + padding: 1px; + font-size: 12px; +} + +.textbox-search-clear { + list-style-image: url(chrome://global/skin/icons/searchfield-cancel.svg); + -moz-image-region: rect(0, 14px, 14px, 0); + margin-bottom: 1px; +} + +textbox[type="search"].compact { + padding: 0; + font-size: 11px; +} + +textbox[type="search"].compact > .textbox-input-box > .textbox-search-icons > .textbox-search-clear { + width: 11px; +} + +.textbox-search-clear:not([disabled]) { + cursor: default; +} + +.textbox-search-icons:not([selectedIndex="1"]) { + visibility: hidden; +} diff --git a/toolkit/themes/osx/global/toolbar.css b/toolkit/themes/osx/global/toolbar.css new file mode 100644 index 0000000000..f07332d2f3 --- /dev/null +++ b/toolkit/themes/osx/global/toolbar.css @@ -0,0 +1,127 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +toolbox { + /* Setting -moz-appearance:toolbox causes sheets to attach under the + * toolbox and has no other effects. It doesn't render anything. */ + -moz-appearance: toolbox; +} + +toolbar { + min-width: 1px; + min-height: 20px; + -moz-appearance: toolbar; +} + +%ifdef MOZ_AUSTRALIS +menubar:-moz-lwtheme, +toolbar:-moz-lwtheme { + -moz-appearance: none; + background: none; + border-color: transparent; +} +%else +menubar:-moz-lwtheme, +toolbar:-moz-lwtheme { + -moz-appearance: none; + background: none; + border-style: none; +} +%endif + +menubar { + -moz-appearance: dialog; /* For content menubars, "toolbar" is too dark, so we use "dialog". */ + min-width: 1px; +} + +toolbarseparator { + -moz-appearance: none; + margin: 3px 4px; + background: url("chrome://global/skin/toolbar/toolbar-separator.png") transparent repeat-y; + padding: 0; + width: 1px !important; +} + +/* ::::: toolbarpaletteitem ::::: */ + +toolbarpaletteitem { + cursor: grab; +} + +toolbar[iconsize="small"] toolbarpaletteitem[type="spacer"] { + min-width: 24px !important; +} + +toolbarpaletteitem[type="spacer"] { + min-width: 32px !important; +} + +.toolbarpaletteitem-box[type="spacer"] { + border: 1px solid #A3A3A3; + background: url("chrome://global/skin/10pct_transparent_grey.png") repeat; + width: 32px; + margin-top: 18px; +} + +.toolbarpaletteitem-box[type="spring"] { + border: 1px solid #A3A3A3; + background: url("chrome://global/skin/toolbar/spring.png") #FFFFFF no-repeat; + width: 32px; + margin-top: 18px; +} + +.toolbarpaletteitem-box[type="spring"][place="toolbar"] { + background: url("chrome://global/skin/10pct_transparent_grey.png") repeat; +} + +.toolbarpaletteitem-box[type="spacer"][place="toolbar"], +.toolbarpaletteitem-box[type="spring"][place="toolbar"] { + margin: 2px; +} + +.toolbarpaletteitem-box[type="separator"][place="palette"] { + width: 2px; + height: 50px; +} + +.toolbarpaletteitem-box[type="spacer"][place="palette"], +.toolbarpaletteitem-box[type="spring"][place="palette"] { + margin-top: 0; + margin-bottom: 2px; + height: 32px; +} + +.toolbarpaletteitem-box[type="spring"][place="palette"] { + background-position: center; + margin-left: 8px; + margin-right: 8px; +} + +/* ..... drag and drop feedback ..... */ + +toolbarpaletteitem[place="toolbar"] { + margin-left: -2px; + margin-right: -2px; + border-left: 2px solid transparent; + border-right: 2px solid transparent; +} + +toolbarpaletteitem[dragover="left"] { + border-left-color: #000000; +} + +toolbarpaletteitem[dragover="right"] { + border-right-color: #000000; +} + +toolbar[iconsize="small"] toolbarspacer { + min-width: 24px !important; +} + +toolbarspacer { + min-width: 32px !important; +} + diff --git a/toolkit/themes/osx/global/toolbar/spring.png b/toolkit/themes/osx/global/toolbar/spring.png new file mode 100644 index 0000000000..807e1f5e54 Binary files /dev/null and b/toolkit/themes/osx/global/toolbar/spring.png differ diff --git a/toolkit/themes/osx/global/toolbar/toolbar-separator.png b/toolkit/themes/osx/global/toolbar/toolbar-separator.png new file mode 100644 index 0000000000..21e17543a0 Binary files /dev/null and b/toolkit/themes/osx/global/toolbar/toolbar-separator.png differ diff --git a/toolkit/themes/osx/global/toolbarbutton.css b/toolkit/themes/osx/global/toolbarbutton.css new file mode 100644 index 0000000000..ab24387e3c --- /dev/null +++ b/toolkit/themes/osx/global/toolbarbutton.css @@ -0,0 +1,124 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +toolbarbutton { + -moz-box-align: center; + -moz-box-pack: center; + margin: 0 2px; + padding: 3px 2px; + background-color: transparent; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4); +} + +toolbarbutton[open="true"], +toolbarbutton:not([disabled="true"]):active:hover { + text-shadow: none; +} + +.toolbarbutton-text { + margin: 0 !important; /* !important for overriding global.css */ + padding: 0px; + text-align: center; + vertical-align: middle; +} + +toolbarbutton[disabled="true"], +toolbarbutton[disabled="true"]:hover, +toolbarbutton[disabled="true"]:hover:active, +toolbarbutton[disabled="true"][open="true"] { + color: -moz-mac-disabledtoolbartext !important; +} + +/* ::::: toolbarbutton menu ::::: */ + +.toolbarbutton-menu-dropmarker { + -moz-appearance: none !important; + border: none !important; + background-color: transparent !important; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.png"); + padding: 0; + padding-inline-start: 2px; + width: auto; +} + +.toolbarbutton-menu-dropmarker[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.png"); + padding: 0; + padding-inline-start: 2px; +} + +/* ::::: toolbarbutton menu-button ::::: */ + +toolbarbutton[type="menu-button"] { + -moz-box-align: stretch; + -moz-box-orient: horizontal !important; +} + +toolbarbutton[type="menu-button"], +toolbarbutton[type="menu-button"]:hover, +toolbarbutton[type="menu-button"]:hover:active, +toolbarbutton[type="menu-button"][open="true"], +toolbarbutton[type="menu-button"][disabled="true"], +toolbarbutton[type="menu-button"][disabled="true"]:hover, +toolbarbutton[type="menu-button"][disabled="true"]:hover:active { + background-color: transparent; +} + +.toolbarbutton-menubutton-button { + -moz-box-align: center; + -moz-box-pack: center; + -moz-box-orient: vertical; + text-shadow: inherit; +} + +/* ::::: toolbarbutton badged ::::: */ + +.toolbarbutton-badge { + background-color: #d90000; + font-size: 9px; + padding: 1px 2px; + color: #fff; + border-radius: 2px; + box-shadow: 0 1px 0 hsla(0, 100%, 100%, .2) inset, + 0 -1px 0 hsla(0, 0%, 0%, .1) inset, + 0 1px 0 hsla(206, 50%, 10%, .2); + margin: -6px 0 0 !important; + margin-inline-end: -6px !important; + min-width: 14px; + max-width: 28px; + line-height: 10px; + text-align: center; + -moz-stack-sizing: ignore; +} + +.toolbarbutton-badge:-moz-window-inactive { + background-color: rgb(230,230,230); + box-shadow: none; + color: rgb(192,192,192); +} + +toolbar[mode="icons"] > *|* > .toolbarbutton-badge { + margin-inline-end: -10px !important; +} + +/* .......... dropmarker .......... */ + +.toolbarbutton-menubutton-dropmarker { + -moz-appearance: none; + border: none; + background-color: transparent !important; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.png"); + width: auto; + padding: 0 5px; +} + +.toolbarbutton-menubutton-dropmarker[disabled="true"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.png"); +} + +toolbarbutton.tabbable { + -moz-user-focus: normal !important; +} diff --git a/toolkit/themes/osx/global/tree.css b/toolkit/themes/osx/global/tree.css new file mode 100644 index 0000000000..472a51fc91 --- /dev/null +++ b/toolkit/themes/osx/global/tree.css @@ -0,0 +1,296 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include shared.inc +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +tree { + margin: 0px 4px; + color: -moz-DialogText; + background-color: #FFFFFF; + -moz-appearance: listbox; +} + +/* ::::: tree focusring ::::: */ + +.focusring > .tree-stack > .tree-rows > .tree-bodybox { + border: 1px solid transparent; +} + +.focusring:focus > .tree-stack > .tree-rows > .tree-bodybox { + border: 1px solid -moz-mac-focusring; +} + + +/* ::::: tree rows ::::: */ + +treechildren::-moz-tree-row { + border-top: 1px solid transparent; + height: 18px; + background-color: -moz-field; +} + +treechildren:not(.autocomplete-treebody)::-moz-tree-row(multicol, odd) { + background-color: -moz-oddtreerow; +} + +treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected) { + background-color: -moz-mac-secondaryhighlight; +} + +treechildren:not(.autocomplete-treebody)::-moz-tree-row(selected, focus) { + background-color: Highlight; + color: HighlightText; +} + +tree[seltype="cell"] > treechildren::-moz-tree-row, +tree[seltype="text"] > treechildren::-moz-tree-row { + border-top: none; + background-color: transparent; +} + +/* ::::: tree cells ::::: */ + +treechildren::-moz-tree-cell { + padding: 0px 2px 0px 2px; +} + +tree[seltype="cell"] > treechildren::-moz-tree-cell-text, +tree[seltype="text"] > treechildren::-moz-tree-cell-text, +treechildren::-moz-tree-cell-text { + color: inherit; +} + +tree[seltype="cell"] > treechildren::-moz-tree-cell { + padding: 0px 1px 0px 1px; +} + +tree[seltype="text"] > treechildren::-moz-tree-cell-text { + padding: 0px 1px 1px 1px; +} + +treechildren::-moz-tree-cell-text(selected) { + color: -moz-DialogText; +} + +tree[seltype="cell"] > treechildren::-moz-tree-cell(active, selected) { + background-color: -moz-mac-secondaryhighlight; + +} +tree[seltype="cell"] > treechildren::-moz-tree-cell-text(active, selected) { + color: -moz-DialogText; +} + +tree[seltype="text"] > treechildren::-moz-tree-cell-text(active, selected) { + background-color: -moz-mac-secondaryhighlight; + color: -moz-DialogText; +} + +treechildren::-moz-tree-cell-text(selected, focus) { + color: HighlightText; +} + +tree[seltype="cell"] > treechildren::-moz-tree-cell(active, selected, focus) { + background-color: Highlight; +} +tree[seltype="cell"] > treechildren::-moz-tree-cell-text(active, selected, focus) { + color: HighlightText; +} + +tree[seltype="text"] > treechildren::-moz-tree-cell-text(active, selected, focus) { + background-color: Highlight; + color: HighlightText; +} + +/* ::::: lines connecting cells ::::: */ + +treechildren::-moz-tree-line { + /* XXX there should be no border on Mac, but trees currently + paint the line black by default, so I'll just leave this + for now. */ + visibility: hidden; + border: 1px dotted grey; +} + + +/* ::::: tree separator ::::: */ + +treechildren::-moz-tree-separator { + border-top: 1px dashed #C7C7C7; + margin: 0 2px; +} + + +/* ::::: drop feedback ::::: */ + +tree[seltype="cell"] > treechildren::-moz-tree-cell(primary, dropOn), +tree[seltype="text"] > treechildren::-moz-tree-cell(primary, dropOn), +treechildren::-moz-tree-cell(primary, dropOn) { + background-color: #A1A1A1 !important; + color: #FFF !important; + background-image: none; +} +tree[seltype="cell"] > treechildren::-moz-tree-cell-text(primary, dropOn), +tree[seltype="text"] > treechildren::-moz-tree-cell-text(primary, dropOn), +treechildren::-moz-tree-cell-text(primary, dropOn) { + color: #FFF !important; +} + +treechildren::-moz-tree-drop-feedback { + background-color: #A1A1A1; + width: 50px; + height: 2px; + margin-inline-start: 5px; +} + +/* ::::: tree progress meter ::::: */ + +treechildren::-moz-tree-progressmeter { + margin: 2px 4px; + border: 2px solid; + -moz-border-top-colors: #AAAAAA #000000; + -moz-border-right-colors: #FFFFFF #000000; + -moz-border-bottom-colors: #FFFFFF #000000; + -moz-border-left-colors: #AAAAAA #000000; +} + +treechildren::-moz-tree-cell-text(progressmeter) { + margin: 2px 4px; + -moz-appearance: progressbar; +} + +/* ::::: tree columns ::::: */ + +treecol, +treecolpicker { + -moz-appearance: treeheadercell; + -moz-box-align: center; + -moz-box-pack: center; + border: 2px solid; + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow; + background-color: -moz-Dialog; + color: -moz-DialogText; + padding: 0px 4px; +} + +.treecol-image { + padding: 0px 1px; +} + +.treecol-text { + margin: 0px !important; +} + +treecol[hideheader="true"] { + -moz-appearance: none; + border: none; + padding: 0; + max-height: 0px; +} + +/* ..... internal box ..... */ + +treecol:hover:active, +treecolpicker:hover:active { + border-top: 2px solid; + border-bottom: 1px solid; + border-inline-start: 2px solid; + border-inline-end: 1px solid; + -moz-border-top-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-right-colors: ThreeDDarkShadow; + -moz-border-bottom-colors: ThreeDDarkShadow; + -moz-border-left-colors: ThreeDDarkShadow ThreeDShadow; + background-color: #666666; +} + +/* ::::: column drag and drop styles ::::: */ + +treecol[dragging="true"] { + -moz-border-top-colors: ThreeDDarkShadow ThreeDShadow !important; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow!important; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow !important; + -moz-border-left-colors: ThreeDDarkShadow ThreeDShadow !important; + padding: 0px 4px !important; + background-color: ThreeDShadow !important; + color: ThreeDHighlight !important; +} + +treecol[insertafter="true"]:-moz-locale-dir(ltr), +treecol[insertbefore="true"]:-moz-locale-dir(rtl) { + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; +} + +treecol[insertafter="true"]:-moz-locale-dir(rtl), +treecol[insertbefore="true"]:-moz-locale-dir(ltr) { + -moz-border-left-colors: ThreeDDarkShadow ThreeDShadow; +} + +treechildren::-moz-tree-column(insertbefore) { + border-inline-start: 1px solid ThreeDShadow; +} + +treechildren::-moz-tree-column(insertafter) { + border-inline-end: 1px solid ThreeDShadow; +} + +/* ::::: column picker ::::: */ + +.tree-columnpicker-icon { + list-style-image: url("chrome://global/skin/tree/columnpicker.gif"); +} + +/* ::::: twisty ::::: */ + +treechildren::-moz-tree-twisty { + -moz-appearance: treetwisty; + padding-inline-end: 2px; +} + +treechildren::-moz-tree-twisty(open) { + -moz-appearance: treetwistyopen; +} + +treechildren::-moz-tree-twisty(Name, separator) { + -moz-appearance: none; +} + +treechildren::-moz-tree-indentation { + width: 16px; +} + +/* ::::: gridline style ::::: */ + +treechildren.gridlines::-moz-tree-cell { + border-inline-end: 1px solid GrayText; + border-bottom: 1px solid GrayText; +} + +treechildren.gridlines::-moz-tree-row { + border: none; +} + +/* ::::: editable tree ::::: */ + +.tree-input { + -moz-appearance: none; + border-width: 0; + box-shadow: @focusRingShadow@; + margin: 0; + margin-inline-start: -2px; + padding: 2px 1px 1px; +} + +treechildren::-moz-tree-cell(active, selected, focus, editing), +tree[seltype="cell"] > treechildren::-moz-tree-cell(active, selected, focus, editing), +tree[seltype="text"] > treechildren::-moz-tree-cell(active, selected, focus, editing) { + background-color: transparent; + border: none; +} + +treechildren::-moz-tree-cell-text(active, selected, editing) { + opacity: 0; +} diff --git a/toolkit/themes/osx/global/tree/arrow-disclosure.svg b/toolkit/themes/osx/global/tree/arrow-disclosure.svg new file mode 100644 index 0000000000..0fee858071 --- /dev/null +++ b/toolkit/themes/osx/global/tree/arrow-disclosure.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + diff --git a/toolkit/themes/osx/global/tree/columnpicker.gif b/toolkit/themes/osx/global/tree/columnpicker.gif new file mode 100644 index 0000000000..167f3789af Binary files /dev/null and b/toolkit/themes/osx/global/tree/columnpicker.gif differ diff --git a/toolkit/themes/osx/global/tree/folder.png b/toolkit/themes/osx/global/tree/folder.png new file mode 100644 index 0000000000..8f21ff790a Binary files /dev/null and b/toolkit/themes/osx/global/tree/folder.png differ diff --git a/toolkit/themes/osx/global/tree/folder@2x.png b/toolkit/themes/osx/global/tree/folder@2x.png new file mode 100644 index 0000000000..c07acf5ffb Binary files /dev/null and b/toolkit/themes/osx/global/tree/folder@2x.png differ diff --git a/toolkit/themes/osx/global/viewbuttons.css b/toolkit/themes/osx/global/viewbuttons.css new file mode 100644 index 0000000000..bb407a64ed --- /dev/null +++ b/toolkit/themes/osx/global/viewbuttons.css @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include shared.inc + +#topBar { + -moz-appearance: toolbar; +} + +.viewGroupWrapper { + -moz-box-align: center; + -moz-box-pack: center; +} + +#viewGroup { + margin: 4px 0 9px; +} + +#viewGroup > radio, +#viewGroup > toolbarbutton { + -moz-box-orient: vertical; + -moz-box-align: center; + -moz-appearance: toolbarbutton; + font: menu; + text-shadow: @loweredShadow@; + margin: 0; + padding: 0 1px; + height: 22px; +} + +#viewGroup > radio[selected=true], +#viewGroup > toolbarbutton[checked=true] { + color: #FFF !important; + text-shadow: rgba(0, 0, 0, 0.4) 0 1px; +} diff --git a/toolkit/themes/osx/global/wizard.css b/toolkit/themes/osx/global/wizard.css new file mode 100644 index 0000000000..9c5e6200ce --- /dev/null +++ b/toolkit/themes/osx/global/wizard.css @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +wizard { + padding: 14px; +} + +#header { + display: inline !important; +} + +.wizard-header { + -moz-appearance: dialog; +} + +.wizard-header-box-1 { + color: #000; +} + +.wizard-header-box-text { + padding: 6px 10px; + font: menu; + font-weight: bold; +} + +.wizard-header-label { + margin-left: 23px; + font-weight: bold; +} + +.wizard-header-box-icon { + margin-top: 3px; + margin-inline-end: 20px; + margin-bottom: 0; + margin-inline-start: 3px; +} + +wizard[branded="true"] .wizard-header-icon { + list-style-image: url("chrome://branding/content/icon48.png"); +} + +.wizard-page-box { + padding: 15px 23px; + -moz-appearance: dialog; +} + +.wizard-buttons-separator { + margin: 0 !important; + border-bottom: 1px solid #fff !important; +} + +.wizard-buttons-btm { + padding: 3px 6px 6px; +} + +.wizard-button { + font: menu !important; +} + diff --git a/toolkit/themes/osx/mochitests/.eslintrc.js b/toolkit/themes/osx/mochitests/.eslintrc.js new file mode 100644 index 0000000000..2c669d844e --- /dev/null +++ b/toolkit/themes/osx/mochitests/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../testing/mochitest/chrome.eslintrc.js" + ] +}; diff --git a/toolkit/themes/osx/mochitests/chrome.ini b/toolkit/themes/osx/mochitests/chrome.ini new file mode 100644 index 0000000000..b7c425bc70 --- /dev/null +++ b/toolkit/themes/osx/mochitests/chrome.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_bug510426.xul] diff --git a/toolkit/themes/osx/mochitests/test_bug510426.xul b/toolkit/themes/osx/mochitests/test_bug510426.xul new file mode 100644 index 0000000000..4294ce42de --- /dev/null +++ b/toolkit/themes/osx/mochitests/test_bug510426.xul @@ -0,0 +1,54 @@ + + + + + + + + + diff --git a/toolkit/themes/osx/moz.build b/toolkit/themes/osx/moz.build new file mode 100644 index 0000000000..fab1daff25 --- /dev/null +++ b/toolkit/themes/osx/moz.build @@ -0,0 +1,8 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ['global', 'mozapps'] + +MOCHITEST_CHROME_MANIFESTS += ['mochitests/chrome.ini'] diff --git a/toolkit/themes/osx/mozapps/downloads/buttons.png b/toolkit/themes/osx/mozapps/downloads/buttons.png new file mode 100644 index 0000000000..04da26a252 Binary files /dev/null and b/toolkit/themes/osx/mozapps/downloads/buttons.png differ diff --git a/toolkit/themes/osx/mozapps/downloads/downloadIcon.png b/toolkit/themes/osx/mozapps/downloads/downloadIcon.png new file mode 100644 index 0000000000..42dc4943d7 Binary files /dev/null and b/toolkit/themes/osx/mozapps/downloads/downloadIcon.png differ diff --git a/toolkit/themes/osx/mozapps/downloads/downloads.css b/toolkit/themes/osx/mozapps/downloads/downloads.css new file mode 100644 index 0000000000..3ba246c1fc --- /dev/null +++ b/toolkit/themes/osx/mozapps/downloads/downloads.css @@ -0,0 +1,123 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../../global/shared.inc + +#downloadView { + -moz-appearance: none; + margin: 0; + padding: 0; + border-width: 0; +} + +/* Download View Items */ +richlistitem[type="download"] { + padding: 5px; + min-height: 44px !important; + border: 1px solid transparent; +} + +richlistitem[type="download"]:not([selected="true"]):nth-child(odd) { + background-color: -moz-oddtreerow; +} + +richlistitem[type="download"] .dateTime, +richlistitem[type="download"] .status { + font-size: smaller; + color: #555; +} + +richlistitem[selected="true"][type="download"] { + outline: none; +} + +richlistbox:focus > richlistitem[selected="true"][type="download"] .dateTime, +richlistbox:focus > richlistitem[selected="true"][type="download"] .status { + color: highlighttext; +} + + +richlistitem[type="download"] button { + -moz-appearance: none; + min-height: 16px; + min-width: 16px; + max-height: 16px; + max-width: 16px; + padding: 0; + margin: 0 1px 0 1px; +} + +/** + * Images for buttons in the interface + */ +richlistitem[type="download"] button { + list-style-image: url(chrome://mozapps/skin/downloads/buttons.png); +} +.cancel { + -moz-image-region: rect(0px, 16px, 16px, 0px); +} +.cancel:hover { + -moz-image-region: rect(0px, 32px, 16px, 16px); +} +.cancel:hover:active { + -moz-image-region: rect(0px, 48px, 16px, 32px); +} + +.pause { + -moz-image-region: rect(48px, 16px, 64px, 0px); +} +.pause:hover { + -moz-image-region: rect(48px, 32px, 64px, 16px); +} +.pause:not([disabled="true"]):hover:active { + -moz-image-region: rect(48px, 48px, 64px, 32px); +} +.pause[disabled="true"] { + -moz-image-region: rect(48px, 16px, 64px, 0px); +} + +.resume { + -moz-image-region: rect(16px, 16px, 32px, 0px); +} +.resume:hover { + -moz-image-region: rect(16px, 32px, 32px, 16px); +} +.resume:hover:active { + -moz-image-region: rect(16px, 48px, 32px, 32px); +} + +.retry { + -moz-image-region: rect(32px, 16px, 48px, 0px); +} +.retry:hover { + -moz-image-region: rect(32px, 32px, 48px, 16px); +} +.retry:hover:active { + -moz-image-region: rect(32px, 48px, 48px, 32px); +} + +.blockedIcon { + list-style-image: url(chrome://global/skin/icons/Error.png); +} + +/* prevent flickering when changing states */ +.downloadTypeIcon { + height: 32px; + width: 32px; + padding-inline-end: 2px; +} + +#search { + -moz-box-pack: end; + padding-inline-end: 4px; + -moz-appearance: statusbar; +} + +#clearListButton { + -moz-appearance: toolbarbutton; + min-height: 18px; + min-width: 0; + margin: 0 6px; + text-shadow: @loweredShadow@; +} diff --git a/toolkit/themes/osx/mozapps/downloads/unknownContentType.css b/toolkit/themes/osx/mozapps/downloads/unknownContentType.css new file mode 100644 index 0000000000..28d01b57af --- /dev/null +++ b/toolkit/themes/osx/mozapps/downloads/unknownContentType.css @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#unknownContentType { + font: menu; +} + +description { + font-weight: bold; +} + +.plain { + background-color: transparent; + background-image: none; + border: none; +} + +#contentTypeImage { + margin-right: 3px; + width: 16px; +} + +#container > .small-indent { + margin-left: 0px; +} + +.small-indent label { + margin-left: 0px; +} diff --git a/toolkit/themes/osx/mozapps/extensions/about.css b/toolkit/themes/osx/mozapps/extensions/about.css new file mode 100644 index 0000000000..cfabd47dba --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/about.css @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#genericAbout { + padding: 0px; + min-height: 200px; + max-height: 400px; + width: 30em; +} + +#clientBox { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +.basic-info { + padding: 10px; +} + +#extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 64px; + max-height: 64px; + -moz-margin-end: 6px; +} + +#genericAbout[addontype="theme"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#genericAbout[addontype="locale"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#genericAbout[addontype="plugin"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#genericAbout[addontype="dictionary"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#extensionName { + font-size: 200%; + font-weight: bolder; +} + +#extensionVersion { + font-weight: bold; +} + +#extensionDescription { + margin-top: 4px; +} + +#groove { + margin-top: 8px; +} + +#extensionDetailsBox { + overflow: auto; + min-height: 100px; +} + +.boxIndent { + -moz-margin-start: 18px; +} + +#extensionCreator, .contributor { + margin: 0px; +} + +.sectionTitle { + padding: 2px 0px 3px 0px; + margin-top: 3px; + font-weight: bold; +} diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-error.png b/toolkit/themes/osx/mozapps/extensions/alerticon-error.png new file mode 100644 index 0000000000..8740e4911a Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-error.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png b/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png new file mode 100644 index 0000000000..2c5f628ab6 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png b/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png new file mode 100644 index 0000000000..a186c6b7ad Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png b/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png new file mode 100644 index 0000000000..75ea826f91 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/blocklist.css b/toolkit/themes/osx/mozapps/extensions/blocklist.css new file mode 100644 index 0000000000..b241c94468 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/blocklist.css @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +richlistitem { + padding-top: 6px; + padding-bottom: 6px; + -moz-padding-start: 7px; + -moz-padding-end: 7px; + border-bottom: 1px solid #C0C0C0; +} + +.addon-name-version { + font-size: 110%; +} + +.blockedLabel { + font-weight: bold; + font-style: italic; +} diff --git a/toolkit/themes/osx/mozapps/extensions/cancel.png b/toolkit/themes/osx/mozapps/extensions/cancel.png new file mode 100644 index 0000000000..0d98ab2359 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/cancel.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-available.png b/toolkit/themes/osx/mozapps/extensions/category-available.png new file mode 100644 index 0000000000..d1b737ab05 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-available.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png b/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png new file mode 100644 index 0000000000..54ae4f93fc Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-discover.png b/toolkit/themes/osx/mozapps/extensions/category-discover.png new file mode 100644 index 0000000000..a6f5b49b37 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-discover.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-experiments.png b/toolkit/themes/osx/mozapps/extensions/category-experiments.png new file mode 100644 index 0000000000..a9d00545ef Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-plugins.png b/toolkit/themes/osx/mozapps/extensions/category-plugins.png new file mode 100644 index 0000000000..5c4d8bf471 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-plugins.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-recent.png b/toolkit/themes/osx/mozapps/extensions/category-recent.png new file mode 100644 index 0000000000..7ecfc7d4c8 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-recent.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-search.png b/toolkit/themes/osx/mozapps/extensions/category-search.png new file mode 100644 index 0000000000..52e91a7cea Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-search.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-searchengines.png b/toolkit/themes/osx/mozapps/extensions/category-searchengines.png new file mode 100644 index 0000000000..b893cb48a2 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-searchengines.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-service.png b/toolkit/themes/osx/mozapps/extensions/category-service.png new file mode 100644 index 0000000000..997c8541ca Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-service.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png new file mode 100644 index 0000000000..4ad1a1a825 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png new file mode 100644 index 0000000000..54ae4f93fc Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/discover-logo.png b/toolkit/themes/osx/mozapps/extensions/discover-logo.png new file mode 100644 index 0000000000..cd50735a89 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/discover-logo.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/eula.css b/toolkit/themes/osx/mozapps/extensions/eula.css new file mode 100644 index 0000000000..5fb2c52df2 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/eula.css @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; + -moz-margin-end: 6px; +} + +#eula-dialog[addontype="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#eula-dialog[addontype="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#eula-dialog[addontype="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#eula-dialog[addontype="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#heading-container { + -moz-box-align: center; +} + +#heading { + font-size: 120%; +} + +#eula { + -moz-appearance: none; + color: -moz-FieldText; + background-color: -moz-Field; + margin: 1em; + border: 1px solid; + -moz-border-top-colors: ActiveBorder; + -moz-border-right-colors: ActiveBorder; + -moz-border-bottom-colors: ActiveBorder; + -moz-border-left-colors: ActiveBorder; +} + diff --git a/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png new file mode 100644 index 0000000000..a9d00545ef Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png new file mode 100644 index 0000000000..fc6c8a2583 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png b/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png new file mode 100644 index 0000000000..6a76774c7b Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensions.css b/toolkit/themes/osx/mozapps/extensions/extensions.css new file mode 100644 index 0000000000..474cb12d10 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/extensions.css @@ -0,0 +1,1206 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + +%include ../../global/shared.inc + +@namespace html url("http://www.w3.org/1999/xhtml"); + + +/*** global warnings ***/ + +.global-warning-container { + overflow-x: hidden; +} + +.global-warning { + -moz-box-align: center; + padding: 0 8px; + color: #916D15; + font-weight: bold; +} + +.global-warning, +.global-warning .button-link { + text-shadow: @loweredShadow@; +} + +#addons-page[warning] .global-warning-container { + background-color: rgba(255, 255, 0, 0.1); + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"); + background-repeat: repeat-x; +} + +#detail-view .global-warning { + padding: 4px 12px; + min-height: 31px; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); +} + +@media (max-width: 600px) { + .global-warning-text { + display: none; + } + + .global-warning .warning-icon { + background-color: rgba(255, 255, 255, 0.7); + box-shadow: 0px 0px 2px 4px rgba(255, 255, 255, 0.7); + border-radius: 10px; + } +} + +/*** global informations ***/ +#addons-page .global-info-container { + background-color: #e3e6eb; + border-top-right-radius: 5px; + border-top-left-radius: 5px; +} + +/* Plugins aren't yet disabled by safemode (bug 342333), + so don't show that warning when viewing plugins. */ +#addons-page[warning="safemode"] .view-pane[type="plugin"] .global-warning-container, +#addons-page[warning="safemode"] #detail-view[loading="true"] .global-warning-container { + background-color: inherit; + background-image: none; +} + + +/*** notification icons ***/ + +.warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.error-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-error.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.pending-icon, +.info-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-positive.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.addon-view[pending="disable"] .pending-icon, +.addon-view[pending="uninstall"] .pending-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + + +/*** view alert boxes ***/ + +.alert-container { + -moz-box-align: center; +} + +.alert-spacer-before { + -moz-box-flex: 1; +} + +.alert-spacer-after { + -moz-box-flex: 3; +} + +.alert { + -moz-box-align: center; + padding: 10px; + color: #373D48; + font-size: 12px; + border: 1px solid #A8B8D1; + border-radius: 8px; + background-image: linear-gradient(rgba(255, 255, 255, 0.7), rgba(236, 241, 247, 0.7)); + background-clip: padding-box; + box-shadow: 0 -3px 0 rgba(58, 78, 103, 0.05) inset, + 0 3px 0 rgba(175, 195, 220, 0.3); +} + +.alert .alert-title { + font-weight: bold; + font-size: 200%; + margin-bottom: 15px; +} + +.alert button { + margin: 1em 2em; +} + +.loading { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + padding-left: 20px; + padding-right: 20px; +} + + + +/*** category selector ***/ + +#categories { + -moz-appearance: none; + border: none; + -moz-margin-end: -1px; + background-color: transparent; + position: relative; + margin-top: 31px; +} + +.category { + -moz-appearance: none; + color: #252F3B; + border-width: 1px; + border-style: solid; + border-color: transparent; + padding: 10px 4px; + -moz-box-align: center; + overflow: hidden; + min-height: 0; +} + +.category:-moz-locale-dir(ltr) { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; +} + +.category:-moz-locale-dir(rtl) { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; +} + +.category[disabled] { + border-top: 0; + border-bottom: 0; + height: 0; + opacity: 0; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category:not([disabled]) { + height: 52px; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category[selected] { + background-color: rgba(255, 255, 255, 0.35); + color: -moz-dialogtext; + border-color: rgba(50, 65, 92, 0.4); + -moz-border-end-color: #C9CFD7; +} + +.category-name { + font-size: 150%; +} + +/* Maximize the size of the viewport when the window is small */ +@media (max-width: 800px) { + .category-name { + display: none; + } +} + +.category-badge { + background-color: #55D4FF; + padding: 2px 8px; + margin: 6px 0; + border-radius: 10000px; + color: #FFF; + font-weight: bold; + text-align: center; +} + +.category-badge[value="0"] { + visibility: hidden; +} + +.category-icon { + width: 32px; + height: 32px; + -moz-margin-start: 6px; +} + +#category-search > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-search.png"); +} +#category-discover > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-discover.png"); +} +#category-locale > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-languages.png"); +} +#category-searchengine > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-searchengines.png"); +} +#category-extension > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png"); +} +#category-service > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-service.png"); +} +#category-theme > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png"); +} +#category-plugin > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png"); +} +#category-dictionary > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); +} +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} +#category-availableUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); +} +#category-recentUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png"); +} + + +/*** header ***/ + +#header { + margin-bottom: 18px; +} + +.nav-button { + list-style-image: url(chrome://mozapps/skin/extensions/navigation.png); +} + +#back-btn:-moz-locale-dir(ltr), +#forward-btn:-moz-locale-dir(rtl) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; + -moz-image-region: rect(0, 20px, 20px, 0); + padding-right: 3px; +} + +#back-btn:-moz-locale-dir(rtl), +#forward-btn:-moz-locale-dir(ltr) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + -moz-image-region: rect(0, 40px, 20px, 20px); + padding-left: 3px; +} + +#header-utils-btn { + list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities"); + -moz-margin-end: 18px; +} + +#header-utils-btn > .toolbarbutton-menu-dropmarker { + list-style-image: url("chrome://mozapps/skin/extensions/toolbarbutton-dropmarker.png"); + padding: 0; + -moz-margin-start: 2px; +} + +#header-search { + margin: 0; + -moz-appearance: none; + padding: 3px 5px 2px; + border: 1px solid rgba(60,73,97,0.5); + border-radius: 10000px; + box-shadow: inset 0 1px 1px rgba(0,0,0,0.15), 0 1px rgba(255,255,255,0.25); + background: linear-gradient(rgba(255,255,255,0.2), rgba(255,255,255,0.3)); + background-clip: padding-box; +} + +@media (max-width: 600px) { + #header-search { + width: 12em; + } +} + +#header-search[focused] { + box-shadow: @focusRingShadow@, inset 0 1px 1px rgba(0,0,0,0.15); + border-color: -moz-mac-focusring; +} + +#header-search > .textbox-input-box { + -moz-padding-start: 15px; + background: url("chrome://mozapps/skin/extensions/search.png") left no-repeat; +} + +#header-search > .textbox-input-box:-moz-locale-dir(rtl) { + background-position: right; +} + +#header-search > .textbox-input-box > html|*.textbox-input::-moz-placeholder { + color: #5C6470; + opacity: 1.0; +} + +.view-header { + padding: 4px; + margin: 0; + min-height: 31px; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); + background-image: linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.05)); +} + + +/*** sorters ***/ + +.sort-controls { + -moz-appearance: none; +} + +.sorter { + -moz-appearance: none; + border: none; + color: #41434B; + background-color: transparent; + border-radius: 10000px; + padding: 0 6px; + margin: 0 6px; + min-width: 12px !important; + -moz-box-direction: reverse; +} + +.sorter[checkState="1"], +.sorter[checkState="2"], +.sorter:active:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; + box-shadow: inset #A3A6AC 0 1px 1px, @loweredShadow@; +} + +.sorter:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; +} + +.sorter[checkState="1"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.sorter[checkState="2"] { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.sorter .button-icon { + -moz-margin-start: 4px; +} + + +/*** discover view ***/ + +.discover-spacer-before, +.discover-spacer-after { + -moz-box-flex: 1; +} + +#discover-error .alert { + max-width: 45em; + -moz-box-flex: 1; +} + +.discover-logo { + list-style-image: url("chrome://mozapps/skin/extensions/discover-logo.png"); + -moz-margin-end: 15px; +} + +.discover-title { + font-weight: bold; + font-size: 24px; + font-family: MetaWebPro-Book, "Trebuchet MS", sans-serif; + margin: 0 0 15px 0; +} + +.discover-description { + text-align: justify; + margin: 0 0 15px 0; +} + +.discover-footer { + text-align: justify; +} + + +/*** list ***/ + +.list { + -moz-appearance: none; + margin: 0; + border: none; + background-color: transparent; +} + +.addon { + border-bottom: 1px solid #B6B1B9; + padding: 5px; + color: #373D48; +} + +.details { + cursor: pointer; + margin: 0; + -moz-margin-start: 10px; +} + +.icon-container { + width: 48px; + height: 48px; + margin: 3px 7px; + -moz-box-align: center; + -moz-box-pack: center; +} + +.icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; +} + +.addon[active="false"] .icon { + filter: grayscale(1); +} + +.addon-view[type="theme"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-view[type="locale"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-view[type="plugin"] .icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-view[type="dictionary"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + +.name-container { + font-size: 150%; + margin-bottom: 0; + font-weight: bold; + color: #000; + text-shadow: @loweredShadow@; + -moz-box-align: end; + -moz-box-flex: 1; +} + +.creator { + font-weight: bold; +} + +.creator .text-link { + color: #0066CC; +} + +.description-container { + margin-top: 8px; + -moz-margin-start: 6px; + -moz-box-align: center; +} + +.description { + margin: 0; +} + +.warning, +.pending, +.error { + -moz-margin-start: 48px; + font-weight: bold; + text-shadow: @loweredShadow@; + -moz-box-align: center; +} + +.content-container, +.basicinfo-container { + -moz-box-align: start; +} + +.addon[status="installing"] > .content-container { + -moz-box-align: stretch; +} + +.update-info-container { + -moz-box-align: center; +} + +.advancedinfo-container, +.update-available { + -moz-box-align: end; +} + +.install-status-container { + -moz-box-pack: end; + -moz-box-align: end; +} + +.name-outer-container { + -moz-box-pack: center; +} + +.relnotes-toggle-container, +.icon-outer-container { + -moz-box-pack: start; +} + +.status-container, +.control-container { + -moz-box-pack: end; +} + +.addon-view .warning { + color: #916D15; +} + +.addon-view .error { + color: #864441; +} + +.addon-view .pending { + color: #1B7123; +} + +.addon-view[pending="disable"] .pending, +.addon-view[pending="uninstall"] .pending { + color: #62666E; +} + +.addon-view[notification="warning"] { + background-image: linear-gradient(rgba(255, 255, 0, 0.2), rgba(255, 255, 0, 0.1)); +} + +.addon-view[notification="error"] { + background-image: linear-gradient(rgba(255, 0, 0, 0.2), rgba(255, 0, 0, 0.1)); +} + +.addon-view[notification="info"] { + background-image: linear-gradient(rgba(0, 0, 255, 0.2), rgba(0, 0, 255, 0.1)); +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: linear-gradient(rgba(0, 255, 0, 0.2), rgba(0, 255, 0, 0.1)); +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: linear-gradient(rgba(128, 128, 128, 0.2), rgba(128, 128, 128, 0.1)); +} + +.addon .relnotes-container { + -moz-box-align: start; + height: 0; + overflow: hidden; + opacity: 0; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon[show-relnotes] .relnotes-container { + opacity: 1; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon .relnotes-header { + font-weight: bold; + margin: 10px 0; +} + +.addon .relnotes-toggle { + -moz-appearance: none; + border: none; + background: transparent; + font-weight: bold; + -moz-box-direction: reverse; + cursor: pointer; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.addon .relnotes-toggle > .button-box > .button-icon { + -moz-padding-start: 4px; +} + +.addon[show-relnotes] .relnotes-toggle { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.addon[active="false"] { + background-color: rgba(135, 135, 135, 0.1); + background-image: linear-gradient(rgba(135, 135, 135, 0), + rgba(135, 135, 135, 0.1)); +} + +.addon-view[active="false"], +.addon-view[active="false"] .name-container { + color: #686A6B; +} + +.addon-view[notification="warning"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"), + linear-gradient(rgba(255, 255, 0, 0.04), + rgba(255, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[notification="warning"][native="false"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-compatibility.png"), + linear-gradient(rgba(255, 128, 0, 0.04), + rgba(255, 128, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[notification="error"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"), + linear-gradient(rgba(255, 0, 0, 0.04), + rgba(255, 0, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-positive.png"), + linear-gradient(rgba(0, 255, 0, 0.04), + rgba(0, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative.png"), + linear-gradient(rgba(128, 128, 128, 0.04), + rgba(128, 128, 128, 0)); + background-repeat: repeat-x; +} + +.addon[selected] { + background-color: rgba(105, 125, 149, 0.39); + color: black; +} + +.addon[selected] .name-container { + text-shadow: @loweredShadow@; +} + +.addon[active="false"][selected] .name-container { + color: #3F3F3F; +} + + +/*** search view ***/ + +#search-filter { + padding: 5px 20px; + font-size: 120%; + overflow-x: hidden; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); +} + +#search-filter-label { + font-weight: bold; + color: #666; +} + +.search-filter-radio { + -moz-appearance: none; + padding: 0 10px; + margin: 0 3px; + border-radius: 10000px; +} + +.search-filter-radio[selected] { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; + box-shadow: inset #A3A6AC 0 1px 1px, @loweredShadow@; +} + +.search-filter-radio:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; +} + +.search-filter-radio .radio-check { + display: none; +} + +.search-filter-radio .radio-icon { + display: none; +} + +#search-allresults-link { + margin-top: 1em; + margin-bottom: 2em; +} + +/*** detail view ***/ + +#detail-view .loading { + opacity: 0; +} + +#detail-view[loading-extended] .loading { + opacity: 1; + transition-property: opacity; + transition-duration: 1s; +} + +.detail-view-container { + padding: 0 2em 2em 2em; + font-size: 110%; +} + +#detail-notifications { + margin-top: 1em; + margin-bottom: 2em; +} + +#detail-notifications .warning, +#detail-notifications .pending, +#detail-notifications .error { + -moz-margin-start: 0; +} + +#detail-icon-container { + width: 64px; + -moz-margin-end: 10px; + margin-top: 6px; +} + +#detail-icon { + max-width: 64px; + max-height: 64px; +} + +#detail-summary { + margin-bottom: 2em; +} + +#detail-name-container { + font-size: 200%; +} + +#detail-screenshot { + -moz-margin-end: 2em; + max-width: 300px; + max-height: 300px; +} + +#detail-screenshot[loading] { + background-image: url("chrome://global/skin/icons/loading_16.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); + background-position: 50% 50%; + background-repeat: no-repeat; + border-radius: 3px; +} + +#detail-screenshot[loading="error"] { + background-image: url("chrome://global/skin/media/error.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); +} + +#detail-desc-container { + margin-bottom: 2em; +} + +#detail-desc, #detail-fulldesc { + -moz-margin-start: 6px; + /* This is necessary to fix layout issues with multi-line descriptions, see + bug 592712*/ + outline: solid transparent; + white-space: pre-wrap; + min-width: 10em; +} + +#detail-fulldesc { + margin-top: 1em; +} + +#detail-contributions { + border-radius: 5px; + border: 1px solid rgba(50, 65, 92, 0.3); + margin-bottom: 2em; + padding: 1em; + background-color: rgba(255, 255, 255, 0.35); +} + +#detail-contrib-description { + font-style: italic; + margin-bottom: 1em; + color: #373D48; +} + +#detail-contrib-suggested { + color: grey; + font-weight: bold; +} + +#detail-contrib-btn { + -moz-appearance: none; + color: #FFF; + border: 1px solid #3A4EEE; + border-radius: 3px; + list-style-image: url("chrome://mozapps/skin/extensions/heart.png"); + background-color: #2F73EF; + background-image: linear-gradient(rgba(251, 252, 253, 0.70), rgba(246, 247, 248, 0.27) 49%, + rgba(231, 232, 233, 0.25) 51%, rgba(225, 226, 229, 0.1)); +} + +#detail-contrib-btn .button-box { + padding: 0 6px 1px 6px; +} + +#detail-contrib-btn .button-icon { + -moz-margin-end: 3px; +} + +#detail-contrib-btn:not(:active):hover { + border-color: #4271FF; + background-color: #0459F7; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), + 0 0 3.5px hsl(190, 90%, 80%); + transition: background-color .4s ease-in, + border-color .3s ease-in, + box-shadow .3s ease-in; +} + +#detail-contrib-btn:active:hover { + background-color: #8FA1C1; + border-color: rgba(0, 0, 0, 0.65) rgba(0, 0, 0, 0.55) rgba(0, 0, 0, 0.5); + box-shadow: 0 0 6.5px rgba(0, 0, 0, 0.4) inset, + 0 0 2px rgba(0, 0, 0, 0.4) inset; +} + +#detail-grid { + margin-bottom: 2em; +} + +#detail-grid > columns > column:first-child { + min-width: 15em; + max-width: 25em; +} + +.detail-row[first-row="true"], +.detail-row-complex[first-row="true"], +setting[first-row="true"] { + border-top: none; +} + +.detail-row, +.detail-row-complex, +setting { + border-top: 2px solid; + -moz-border-top-colors: rgba(28, 31, 37, 0.2) rgba(255, 255, 255, 0.2); + -moz-box-align: center; + min-height: 30px; +} + +#detail-controls { + margin-bottom: 1em; +} + +#detail-view[active="false"]:not([pending]):not([notification]) { + background-image: linear-gradient(rgba(135, 135, 135, 0.1), + rgba(135, 135, 135, 0)); +} + +setting[first-row="true"] { + margin-top: 2em; +} + +setting { + -moz-box-align: start; +} + +.preferences-alignment { + min-height: 30px; + -moz-box-align: center; +} + +.preferences-description { + font-size: 90.9%; + color: graytext; + margin-top: -2px; + -moz-margin-start: 2em; + white-space: pre-wrap; +} + +.preferences-description:empty { + display: none; +} + +setting[type="radio"] > radiogroup { + -moz-box-orient: horizontal; +} + + +/*** creator ***/ + +.creator > label { + -moz-margin-start: 0; + -moz-margin-end: 0; +} + +.creator > .text-link { + margin-top: 1px; + margin-bottom: 1px; +} + + +/*** rating ***/ + +.meta-rating { + -moz-margin-end: 0; + margin-top: 2px; +} + +.meta-rating > .star { + list-style-image: url("chrome://mozapps/skin/extensions/rating-not-won.png"); + padding: 0 1px; +} + +.meta-rating > .star[on="true"] { + list-style-image: url("chrome://mozapps/skin/extensions/rating-won.png"); +} + + +/*** download progress ***/ + +.download-progress { + background-image: linear-gradient(#DCDEE3, #CBCED6); + border: 1px solid #858898; + border-radius: 3px; + box-shadow: inset #E3E8EC 0 1px 1px, @loweredShadow@; + width: 200px; + height: 21px; + margin: 0 8px; +} + +.download-progress[mode="undetermined"] .progress { + -moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter-undetermined"); +} + +.download-progress[mode="undetermined"] { + border-color: #2E773A; +} + +.download-progress[mode="undetermined"] .status-container { + padding: 0 2px; +} + +.download-progress .start-cap, +.download-progress[complete] .end-cap, +.download-progress[mode="undetermined"] .end-cap, +.download-progress .progress .progress-bar { + -moz-appearance: none; + background-image: linear-gradient(#6AC47E, #4FAC6A); + margin-top: -1px; + margin-bottom: -1px; + border: 1px solid #2E773A; +} + +.download-progress .start-cap { + -moz-margin-start: -1px; + -moz-border-end-width: 0; +} + +.download-progress .end-cap { + -moz-margin-end: -1px; + -moz-border-start-width: 0px !important; +} + +.download-progress .progress .progress-bar { + border-left-width: 0; + border-right-width: 0; + min-height: 21px; +} + +.download-progress .progress { + -moz-appearance: none; + background-color: transparent; + padding: 0; + margin: 0; + border: none; +} + +.download-progress .start-cap, +.download-progress .end-cap { + width: 4px; +} + +.download-progress .start-cap:-moz-locale-dir(ltr), +.download-progress .end-cap:-moz-locale-dir(rtl) { + border-radius: 3px 0 0 3px; +} + +.download-progress .end-cap:-moz-locale-dir(ltr), +.download-progress .start-cap:-moz-locale-dir(rtl) { + border-radius: 0 3px 3px 0; +} + +.download-progress .cancel { + -moz-appearance: none; + background-color: rgba(255, 255, 255, 0.15); + border: 1px solid rgba(0, 0, 0, 0.4); + padding: 3px; + border-radius: 3px; + min-width: 0; + margin: 3px; +} + +.download-progress .cancel .button-text { + display: none; +} + +.download-progress .cancel .button-icon { + -moz-margin-start: 0; +} + +.download-progress .cancel { + list-style-image: url('chrome://mozapps/skin/extensions/cancel.png'); +} + +.download-progress .status-container { + -moz-box-align: center; +} + +.download-progress .status { + text-shadow: @loweredShadow@; +} + + +/*** install status ***/ + +.install-status { + -moz-box-align: center; +} + + +/*** check for updates ***/ + +#updates-container { + -moz-box-align: center; +} + +#updates-installed, +#updates-downloaded { + color: #3C735C; + font-weight: bold; +} + +#update-selected { + margin: 12px; +} + + +/*** buttons ***/ + +.addon-control[disabled="true"]:not(.no-auto-hide) { + display: none; +} + +.no-auto-hide .addon-control { + display: block !important; +} + +.no-auto-hide > .menulist-dropmarker { + -moz-padding-start: 0px !important; +} + +button.button-link { + -moz-appearance: none; + background: transparent; + border: none; + box-shadow: none; + text-decoration: underline; + color: #0066CC; + cursor: pointer; + min-width: 0; + margin: 0 6px; +} + +.text-link { + color: #3386D5; +} + +.button-link:hover, +.text-link:hover { + color: #3DA1FF; +} + +/* Needed to override normal button style from inContent.css */ +button.button-link:not([disabled="true"]):active:hover { + background: transparent; + border: none; + box-shadow: none; +} + +.header-button { + -moz-appearance: none; + padding: 0 4px; + margin: 0; + height: 22px; + border: 1px solid rgba(60,73,97,0.5); + border-radius: @toolbarbuttonCornerRadius@; + box-shadow: inset 0 1px rgba(255,255,255,0.25), 0 1px rgba(255,255,255,0.25); + background: linear-gradient(rgba(255,255,255,0.45), transparent); + background-clip: padding-box; +} + +.header-button .toolbarbutton-text { + display: none; +} + +.header-button[disabled="true"] .toolbarbutton-icon { + opacity: 0.4; +} + +.header-button:not([disabled="true"]):active:hover, +.header-button[open="true"] { + border-color: rgba(45,54,71,0.7); + box-shadow: inset 0 0 4px rgb(45,54,71), 0 1px rgba(255,255,255,0.25); + background-image: linear-gradient(rgba(45,54,71,0.6), transparent); +} + +/*** telemetry experiments ***/ + +#detail-experiment-container { + font-size: 80%; + margin-bottom: 1em; +} + +#detail-experiment-bullet-container, +#detail-experiment-state, +#detail-experiment-time, +.experiment-bullet-container, +.experiment-state, +.experiment-time { + vertical-align: middle; + display: inline-block; +} + +.addon .experiment-bullet, +#detail-experiment-bullet { + fill: rgb(158, 158, 158); +} + +.addon[active="true"] .experiment-bullet, +#detail-view[active="true"] #detail-experiment-bullet { + fill: rgb(106, 201, 20); +} diff --git a/toolkit/themes/osx/mozapps/extensions/heart.png b/toolkit/themes/osx/mozapps/extensions/heart.png new file mode 100644 index 0000000000..655f4c4be7 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/heart.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/localeGeneric.png b/toolkit/themes/osx/mozapps/extensions/localeGeneric.png new file mode 100644 index 0000000000..4d9ac5ad89 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/localeGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/navigation.png b/toolkit/themes/osx/mozapps/extensions/navigation.png new file mode 100644 index 0000000000..ffc40d7e56 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/navigation.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/newaddon.css b/toolkit/themes/osx/mozapps/extensions/newaddon.css new file mode 100644 index 0000000000..5bf04fab1d --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/newaddon.css @@ -0,0 +1,112 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../../global/shared.inc + +@import url("chrome://global/skin/inContentUI.css"); + +#addon-page { + padding: 0; +} + +#addon-scrollbox { + overflow: auto; + -moz-box-orient: vertical; + -moz-box-flex: 1; +} + +#spacer-start { + -moz-box-flex: 1; +} + +#spacer-end { + -moz-box-flex: 3; +} + +#addon-container { + overflow: visible; + max-width: 600px; + margin: 20px; + padding: 30px 90px; +} + +#addon-info { + -moz-box-align: start; + margin: 25px 10px; +} + +#icon { + -moz-margin-end: 10px; + max-width: 64px; + max-height: 64px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +.addon-info[type="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-info[type="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-info[type="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-info[type="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#name { + font-size: 130%; +} + +#author { + color: GrayText; +} + +#location { + color: GrayText; +} + +#warning { + margin-bottom: 25px; + -moz-box-align: start; +} + +#warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + -moz-margin-end: 5px; +} + +#allow { + -moz-margin-start: 84px; + margin-bottom: 20px; +} + +#continuePanel, +#restartPanel { + margin-top: 25px; + -moz-box-align: center; + -moz-box-pack: end; +} + +#continuePanel { + -moz-box-pack: end; +} + +#restartMessage { + text-align: right; +} + +#restartSpacer { + -moz-box-flex: 1; +} + +#later { + color: GrayText; +} diff --git a/toolkit/themes/osx/mozapps/extensions/rating-not-won.png b/toolkit/themes/osx/mozapps/extensions/rating-not-won.png new file mode 100644 index 0000000000..2761f19255 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/rating-not-won.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/rating-won.png b/toolkit/themes/osx/mozapps/extensions/rating-won.png new file mode 100644 index 0000000000..336dd8f6eb Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/rating-won.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/search.png b/toolkit/themes/osx/mozapps/extensions/search.png new file mode 100644 index 0000000000..93196dbbf6 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/search.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/selectAddons.css b/toolkit/themes/osx/mozapps/extensions/selectAddons.css new file mode 100644 index 0000000000..8682b04b51 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/selectAddons.css @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../../global/shared.inc + +.heading { + font-size: 270%; + text-align: center; + margin: 0 120px; +} + +.progress { + margin: 10px 128px; +} + +.progress-label, +#errors-description { + text-align: center; + margin: 0 10px; +} + +#checking-heading, +#update-heading, +#errors-heading { + margin-top: 90px; +} + +#select-heading, +#confirm-heading { + margin-top: 10px; + margin-bottom: 10px; + text-align: center; +} + +#select-description, +#confirm-description { + margin: 10px; +} + +#select-list { + border: 1px solid WindowFrame; + background-color: Window; + margin: 10px; +} + +#select-grid column { + -moz-box-align: center; +} + +#select-grid row { + -moz-box-align: stretch; +} + +#select-grid row:nth-of-type(odd) { + background-color: -moz-oddtreerow; +} + +#select-grid label, +#select-grid checkbox { + margin-top: 0; + margin-bottom: 0; +} + +.select-cell { + -moz-box-align: center; + -moz-box-pack: start; + box-sizing: border-box; +} + +#select-header { + background-color: Window !important; +} + +#select-header .select-cell { + -moz-appearance: treeheadercell; + border: 2px solid; + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow; + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +.select-keep { + -moz-box-pack: center; +} + +.select-icon { + width: 20px; +} + +#select-grid separator { + display: none; +} + +.addon-name, +.addon-action-message, +.addon-action-update { + box-sizing: border-box; + margin: 0; + padding: 2px 6px; +} + +.addon:not([active]) .addon-name, +.addon:not([active]) .addon-action-message, +.addon:not([active]) .addon-action-update { + color: GrayText; +} + +.addon-icon { + height: 16px; + width: 16px; + margin: 2px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); +} + +.addon-icon[type="theme"] { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png"); +} + +.addon-icon[type="plugin"] { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png"); +} + +.addon-icon[type="dictionary"] { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png"); +} + +.action-list { + margin-top: 10px; + -moz-margin-start: 5em; +} + +.action-header { + margin-bottom: 10px; +} + +#confirm .addon { + -moz-margin-start: 3em; + -moz-box-align: center; +} + +.addon:not([active]) .addon-icon, +#disable-list .addon-icon, +#incompatible-list .addon-icon { + filter: grayscale(1); +} + +#footer { + padding: 15px 12px; + -moz-appearance: statusbar; + -moz-window-dragging: drag; +} + +button { + -moz-appearance: toolbarbutton; + min-height: 22px; + margin: 0 6px; + padding: 0; + text-shadow: @loweredShadow@; +} diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-compatibility.png b/toolkit/themes/osx/mozapps/extensions/stripes-compatibility.png new file mode 100644 index 0000000000..dee75516b7 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-compatibility.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-error.png b/toolkit/themes/osx/mozapps/extensions/stripes-error.png new file mode 100644 index 0000000000..1dc2d8504c Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-error.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png b/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png new file mode 100644 index 0000000000..901ab1ec29 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png b/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png new file mode 100644 index 0000000000..370ceec0f2 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-warning.png b/toolkit/themes/osx/mozapps/extensions/stripes-warning.png new file mode 100644 index 0000000000..69463fb1af Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-warning.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png new file mode 100644 index 0000000000..190bb30d71 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/themeGeneric.png b/toolkit/themes/osx/mozapps/extensions/themeGeneric.png new file mode 100644 index 0000000000..be645f76df Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/themeGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png b/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png new file mode 100644 index 0000000000..e7674c62a6 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/update.css b/toolkit/themes/osx/mozapps/extensions/update.css new file mode 100644 index 0000000000..8e92556913 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/update.css @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#alert { + list-style-image: url("chrome://mozapps/skin/update/warning.gif"); +} + +.throbber { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + width: 16px; + height: 16px; + margin-top: 5px; + margin-bottom: 5px; + -moz-margin-start: 5px; + -moz-margin-end: 2px; +} + +.alertBox { + background-color: InfoBackground; + color: InfoText; + border: 1px outset InfoBackground; + margin-left: 3px; + margin-right: 3px; + padding: 5px; +} diff --git a/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css b/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css new file mode 100644 index 0000000000..0a1a84b249 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#xpinstallheader { + margin-bottom: 2em; +} + +.alert-icon { + width: 48px; + height: 48px; + list-style-image: url("chrome://global/skin/icons/warning-large.png"); + margin-top: 0 !important; + margin-bottom: 6px !important; + -moz-margin-start: 6px !important; + -moz-margin-end: 20px !important; +} + +#itemList { + -moz-appearance: listbox; + margin: 3px 4px 10px 4px; + height: 14em; +} + +#itemWarningIntro { + -moz-margin-start: 8px; +} + +#dialogContentBox { + padding: 5px; +} + +installitem { + padding: 5px 0 5px 5px; + border-bottom: 1px dotted #C0C0C0; + margin-bottom: 5px; +} + +.warning { + font-weight: bold; + font-size: 1.25em; + margin-bottom: 1em; +} + +.xpinstallIconContainer { + width: 32px; + height: 32px; + -moz-margin-end: 5px; +} + +.xpinstallItemName { + font-weight: bold; +} + +.xpinstallItemSigned { + font-style: italic; + font-size: 0.9em; +} + +.xpinstallItemURL { + -moz-appearance: none; + border: none; + background-color: Window; + margin-top: 2px; + margin-bottom: 1px; + -moz-margin-start: 6px; + -moz-margin-end: 5px; +} + +.xpinstallItemIcon { + max-width: 32px; + max-height: 32px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +installitem[type="theme"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +installitem[type="locale"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +installitem[type="plugin"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +installitem[type="dictionary"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} diff --git a/toolkit/themes/osx/mozapps/handling/handling.css b/toolkit/themes/osx/mozapps/handling/handling.css new file mode 100644 index 0000000000..9598bedaed --- /dev/null +++ b/toolkit/themes/osx/mozapps/handling/handling.css @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#description-image:not([src]) { + height: 32px; + width: 32px; +} + +richlistitem[type] { + min-height: 36px; /* Don't forget to update the richlistbox height! */ + padding-inline-start: 2px; + } + +richlistitem { + -moz-box-align: center; +} + +richlistbox { + /* 3 items high, plus 4px for top and bottom margins, less 2px for border */ + min-height: 110px; +} + +.name { + font-weight: bold; +} + +.description { + color: GrayText; +} diff --git a/toolkit/themes/osx/mozapps/jar.mn b/toolkit/themes/osx/mozapps/jar.mn new file mode 100644 index 0000000000..eabd2eddb5 --- /dev/null +++ b/toolkit/themes/osx/mozapps/jar.mn @@ -0,0 +1,79 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +toolkit.jar: +#include ../../shared/mozapps.inc.mn + skin/classic/mozapps/downloads/buttons.png (downloads/buttons.png) + skin/classic/mozapps/downloads/downloadIcon.png (downloads/downloadIcon.png) +* skin/classic/mozapps/downloads/downloads.css (downloads/downloads.css) + skin/classic/mozapps/downloads/unknownContentType.css (downloads/unknownContentType.css) + skin/classic/mozapps/extensions/category-search.png (extensions/category-search.png) + skin/classic/mozapps/extensions/category-discover.png (extensions/category-discover.png) + skin/classic/mozapps/extensions/category-languages.png (extensions/localeGeneric.png) + skin/classic/mozapps/extensions/category-searchengines.png (extensions/category-searchengines.png) + skin/classic/mozapps/extensions/category-extensions.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/category-themes.png (extensions/themeGeneric.png) + skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) + skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) + skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) + skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) + skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) + skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) + skin/classic/mozapps/extensions/discover-logo.png (extensions/discover-logo.png) + skin/classic/mozapps/extensions/extensionGeneric.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/extensionGeneric-16.png (extensions/extensionGeneric-16.png) + skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png) + skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) + skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) + skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) + skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) + skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) + skin/classic/mozapps/extensions/rating-won.png (extensions/rating-won.png) + skin/classic/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png) + skin/classic/mozapps/extensions/cancel.png (extensions/cancel.png) + skin/classic/mozapps/extensions/utilities.svg (../../shared/extensions/utilities.svg) + skin/classic/mozapps/extensions/toolbarbutton-dropmarker.png (extensions/toolbarbutton-dropmarker.png) + skin/classic/mozapps/extensions/heart.png (extensions/heart.png) + skin/classic/mozapps/extensions/navigation.png (extensions/navigation.png) + skin/classic/mozapps/extensions/stripes-warning.png (extensions/stripes-warning.png) + skin/classic/mozapps/extensions/stripes-error.png (extensions/stripes-error.png) + skin/classic/mozapps/extensions/stripes-info-positive.png (extensions/stripes-info-positive.png) + skin/classic/mozapps/extensions/stripes-info-negative.png (extensions/stripes-info-negative.png) + skin/classic/mozapps/extensions/alerticon-warning.png (extensions/alerticon-warning.png) + skin/classic/mozapps/extensions/alerticon-error.png (extensions/alerticon-error.png) + skin/classic/mozapps/extensions/alerticon-info-positive.png (extensions/alerticon-info-positive.png) + skin/classic/mozapps/extensions/alerticon-info-negative.png (extensions/alerticon-info-negative.png) + skin/classic/mozapps/extensions/search.png (extensions/search.png) + skin/classic/mozapps/extensions/about.css (extensions/about.css) +* skin/classic/mozapps/extensions/extensions.css (extensions/extensions.css) +* skin/classic/mozapps/extensions/selectAddons.css (extensions/selectAddons.css) + skin/classic/mozapps/extensions/update.css (extensions/update.css) + skin/classic/mozapps/extensions/eula.css (extensions/eula.css) + skin/classic/mozapps/extensions/blocklist.css (extensions/blocklist.css) +* skin/classic/mozapps/extensions/newaddon.css (extensions/newaddon.css) + skin/classic/mozapps/passwordmgr/key.png (passwordmgr/key.png) + skin/classic/mozapps/passwordmgr/key-16.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-64.png (passwordmgr/key-64.png) + skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/notifyPluginGeneric.png) + skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) + skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png) + skin/classic/mozapps/plugins/pluginBlocked-64.png (plugins/pluginBlocked-64.png) + skin/classic/mozapps/plugins/pluginGeneric-16.png (plugins/pluginGeneric-16.png) + skin/classic/mozapps/plugins/pluginHelp-16.png (plugins/pluginHelp-16.png) + skin/classic/mozapps/profile/profileicon.png (profile/profileicon.png) + skin/classic/mozapps/profile/profileSelection.css (profile/profileSelection.css) + skin/classic/mozapps/profile/profileicon-selected.png (profile/profileicon-selected.png) + skin/classic/mozapps/update/buttons.png (update/buttons.png) +* skin/classic/mozapps/update/updates.css (update/updates.css) + skin/classic/mozapps/viewsource/viewsource.css (viewsource/viewsource.css) + skin/classic/mozapps/xpinstall/xpinstallItemGeneric.png (extensions/extensionGeneric.png) + skin/classic/mozapps/xpinstall/xpinstallConfirm.css (extensions/xpinstallConfirm.css) + skin/classic/mozapps/handling/handling.css (handling/handling.css) + +#ifdef MOZ_PHOENIX +[browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: +#elif MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES +[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar: +#endif +% override chrome://mozapps/skin/plugins/notifyPluginCrashed.png chrome://mozapps/skin/plugins/notifyPluginGeneric.png diff --git a/toolkit/themes/osx/mozapps/moz.build b/toolkit/themes/osx/mozapps/moz.build new file mode 100644 index 0000000000..635fa39c99 --- /dev/null +++ b/toolkit/themes/osx/mozapps/moz.build @@ -0,0 +1,6 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key-16.png b/toolkit/themes/osx/mozapps/passwordmgr/key-16.png new file mode 100644 index 0000000000..ac135b847e Binary files /dev/null and b/toolkit/themes/osx/mozapps/passwordmgr/key-16.png differ diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key-64.png b/toolkit/themes/osx/mozapps/passwordmgr/key-64.png new file mode 100644 index 0000000000..0fb69f3828 Binary files /dev/null and b/toolkit/themes/osx/mozapps/passwordmgr/key-64.png differ diff --git a/toolkit/themes/osx/mozapps/passwordmgr/key.png b/toolkit/themes/osx/mozapps/passwordmgr/key.png new file mode 100644 index 0000000000..b5e8afefca Binary files /dev/null and b/toolkit/themes/osx/mozapps/passwordmgr/key.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/notifyPluginGeneric.png b/toolkit/themes/osx/mozapps/plugins/notifyPluginGeneric.png new file mode 100644 index 0000000000..449e081496 Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/notifyPluginGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/pluginBlocked-64.png b/toolkit/themes/osx/mozapps/plugins/pluginBlocked-64.png new file mode 100644 index 0000000000..56b8a3322d Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/pluginBlocked-64.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/pluginBlocked.png b/toolkit/themes/osx/mozapps/plugins/pluginBlocked.png new file mode 100644 index 0000000000..6e8e1761bf Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/pluginBlocked.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/pluginGeneric-16.png b/toolkit/themes/osx/mozapps/plugins/pluginGeneric-16.png new file mode 100644 index 0000000000..6956ffef81 Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/pluginGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/pluginGeneric.png b/toolkit/themes/osx/mozapps/plugins/pluginGeneric.png new file mode 100644 index 0000000000..6ada1616bb Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/pluginGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/plugins/pluginHelp-16.png b/toolkit/themes/osx/mozapps/plugins/pluginHelp-16.png new file mode 100644 index 0000000000..9a577c08f2 Binary files /dev/null and b/toolkit/themes/osx/mozapps/plugins/pluginHelp-16.png differ diff --git a/toolkit/themes/osx/mozapps/profile/profileSelection.css b/toolkit/themes/osx/mozapps/profile/profileSelection.css new file mode 100644 index 0000000000..cc3ab451c7 --- /dev/null +++ b/toolkit/themes/osx/mozapps/profile/profileSelection.css @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + + +@import url("chrome://global/skin/global.css"); + +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +#profiles > listitem { + list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); +} + +#profiles:focus > listitem[selected="true"] { + list-style-image: url("chrome://mozapps/skin/profile/profileicon-selected.png"); +} + +#profiles > listitem > listcell > image { + width: 16px; + height: 16px; +} + +box#managebuttons > button { + min-width: 8em; +} + +#managebuttons { + padding-top: 1em; +} diff --git a/toolkit/themes/osx/mozapps/profile/profileicon-selected.png b/toolkit/themes/osx/mozapps/profile/profileicon-selected.png new file mode 100644 index 0000000000..f3e1f8e110 Binary files /dev/null and b/toolkit/themes/osx/mozapps/profile/profileicon-selected.png differ diff --git a/toolkit/themes/osx/mozapps/profile/profileicon.png b/toolkit/themes/osx/mozapps/profile/profileicon.png new file mode 100644 index 0000000000..f67a43714e Binary files /dev/null and b/toolkit/themes/osx/mozapps/profile/profileicon.png differ diff --git a/toolkit/themes/osx/mozapps/update/buttons.png b/toolkit/themes/osx/mozapps/update/buttons.png new file mode 100644 index 0000000000..04da26a252 Binary files /dev/null and b/toolkit/themes/osx/mozapps/update/buttons.png differ diff --git a/toolkit/themes/osx/mozapps/update/updates.css b/toolkit/themes/osx/mozapps/update/updates.css new file mode 100644 index 0000000000..9bd78ef6f8 --- /dev/null +++ b/toolkit/themes/osx/mozapps/update/updates.css @@ -0,0 +1,171 @@ +%include ../../global/shared.inc + +/* General */ +/* Specify the size for the wizardpage so the billboard has a fixed size. 3rd + party themes should typically specify the same values. */ +wizardpage { + height: 360px; + width: 700px; +} + +/* Remove margin and padding so the billboard will extend to the edge of the + window. 3rd party themes should typically specify the same values. */ +#updates, .wizard-page-box { + margin: 0; + padding: 0; +} + +.update-content { + padding: 6px 12px 12px 12px; +} + +.wizard-header-box-text { + padding: 0; +} + +.wizard-header { + margin: 12px 12px 0 12px; +} + +.wizard-buttons-btm { + padding: 15px 12px; +} + +/* Don't use top margin - it can cause a scrollbar on some pages */ +.wizard-buttons { + padding: 0; + -moz-appearance: statusbar; + -moz-window-dragging: drag; +} + +.wizard-buttons button { + -moz-appearance: toolbarbutton; + color: ButtonText; + min-height: 22px; + margin: 0 6px; + padding: 0; + text-shadow: @loweredShadow@; +} + +#finishedBackgroundMore { + margin-bottom: 6px; +} + +.inline-link { + color: -moz-nativehyperlinktext; + text-decoration: none; +} + +.inline-link:hover { + text-decoration: underline; +} + +/* Unsupported Page */ +#unsupportedLabel, #unsupportedLinkLabel { + margin-inline-start: 0; + padding-inline-start: 0; +} + +/* Update Found Basic Page */ +#updateName, #updateFinishedName { + font-weight: bold; + font-size: larger; +} + +/* Downloading Page */ +#downloadStatusLine { + -moz-box-align: center; +} + +#downloadStatus { + height: 3em !important; +} + +#downloadStatusProgress { + padding-right: 5px; +} + +#pauseButton { + list-style-image: url(chrome://mozapps/skin/update/buttons.png); + -moz-image-region: rect(48px, 16px, 64px, 0px); + -moz-appearance: none; + background-color: transparent; + border: none; + min-height: 16px; + min-width: 16px; + max-height: 16px; + max-width: 16px; + margin: 0 1px 0 1px; + padding: 0; +} + +/* !Important must be used otherwise this won't immediately take affect */ +#pauseButton > .button-box { + padding: 0 !important; +} + +#pauseButton:hover { + -moz-image-region: rect(48px, 32px, 64px, 16px); +} + +#pauseButton:not([disabled="true"]):hover:active { + -moz-image-region: rect(48px, 48px, 64px, 32px); +} + +#pauseButton[disabled="true"] { + -moz-image-region: rect(48px, 16px, 64px, 0px); +} + +#pauseButton[paused="true"] { + -moz-image-region: rect(16px, 16px, 32px, 0px); +} + +#pauseButton[paused="true"]:hover { + -moz-image-region: rect(16px, 32px, 32px, 16px); +} + +#pauseButton[paused="true"]:hover:active { + -moz-image-region: rect(16px, 48px, 32px, 32px); +} + +#verificationFailedIcon { + margin-left: 5px; + list-style-image: url("chrome://global/skin/icons/notfound.png"); +} + +/* Error Page */ +#errorReason { + margin-top: 1px; + margin-bottom: 2px; + margin-inline-start: 6px !important; + margin-inline-end: 5px; + font-weight: bold; +} + +/* Update History Window */ +update { + border-bottom: 1px dotted #C0C0C0; +} + +.update-name { + font-weight: bold; +} + +.update-label-column { + -moz-box-align: end; +} + +.update-type { + font-weight: bold; + color: #990000; +} + +#historyItems { + -moz-appearance: listbox; + height: 200px; + margin: 1px 5px 4px 5px; +} + +#historyItems > scrollbox { + margin-bottom: 1px; +} diff --git a/toolkit/themes/osx/mozapps/viewsource/viewsource.css b/toolkit/themes/osx/mozapps/viewsource/viewsource.css new file mode 100644 index 0000000000..76c7d00b9d --- /dev/null +++ b/toolkit/themes/osx/mozapps/viewsource/viewsource.css @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This is for styling the menus of the viewsource window */ diff --git a/toolkit/themes/osx/reftests/482681-ref.xul b/toolkit/themes/osx/reftests/482681-ref.xul new file mode 100644 index 0000000000..62fb4bb8d5 --- /dev/null +++ b/toolkit/themes/osx/reftests/482681-ref.xul @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/toolkit/themes/osx/reftests/482681.xul b/toolkit/themes/osx/reftests/482681.xul new file mode 100644 index 0000000000..6cb9aaeae4 --- /dev/null +++ b/toolkit/themes/osx/reftests/482681.xul @@ -0,0 +1,22 @@ + + + + + + +